Run php script as daemon process

后端 未结 14 1459
-上瘾入骨i
-上瘾入骨i 2020-11-22 11:36

I need to run a php script as daemon process (wait for instructions and do stuff). cron job will not do it for me because actions need to be taken as soon as instruction arr

相关标签:
14条回答
  • 2020-11-22 12:20

    As others have already mentioned, running PHP as a daemon is quite easy, and can be done using a single line of command. But the actual problem is keeping it running and managing it. I've had the same problem quite some time ago and although there are plenty of solutions already available, most of them have lots of dependencies or are difficult to use and not suitable for basic usages. I wrote a shell script that can manage a any process/application including PHP cli scripts. It can be set as a cronjob to start the application and will contain the application and manage it. If it's executed again, for example via the same cronjob, it check if the app is running or not, if it does then simply exits and let its previous instance continue managing the application.

    I uploaded it to github, feel free to use it : https://github.com/sinasalek/EasyDeamonizer

    EasyDeamonizer

    Simply watches over your application (start, restart, log, monitor, etc). a generic script to make sure that your appliation remains running properly. Intentionally it uses process name instread of pid/lock file to prevent all its side effects and keep the script as simple and as stirghforward as possible, so it always works even when EasyDaemonizer itself is restarted. Features

    • Starts the application and optionally a customized delay for each start
    • Makes sure that only one instance is running
    • Monitors CPU usage and restarts the app automatically when it reaches the defined threshold
    • Setting EasyDeamonizer to run via cron to run it again if it's halted for any reason
    • Logs its activity
    0 讨论(0)
  • 2020-11-22 12:22

    There is more than one way to solve this problem.

    I do not know the specifics but perhaps there is another way to trigger the PHP process. For instance if you need the code to run based on events in a SQL database you could setup a trigger to execute your script. This is really easy to do under PostgreSQL: http://www.postgresql.org/docs/current/static/external-pl.html .

    Honestly I think your best bet is to create a Damon process using nohup. nohup allows the command to continue to execute even after the user has logged out:

    nohup php myscript.php &
    

    There is however a very serious problem. As you said PHP's memory manager is complete garbage, it was built with the assumption that a script is only executing for a few seconds and then exists. Your PHP script will start to use GIGABYTES of memory after only a few days. You MUST ALSO create a cron script that runs every 12 or maybe 24 hours that kills and re-spawns your php script like this:

    killall -3 php
    nohup php myscript.php &
    

    But what if the script was in the middle of a job? Well kill -3 is an interrupt, its the same as doing a ctrl+c on the CLI. Your php script can catch this interrupt and exit gracefully using the PHP pcntl library: http://php.oregonstate.edu/manual/en/function.pcntl-signal.php

    Here is an example:

    function clean_up() {
      GLOBAL $lock;
      mysql_close();
      fclose($lock)
      exit();
    }
    pcntl_signal(SIGINT, 'clean_up');
    

    The idea behind the $lock is that the PHP script can open a file with a fopen("file","w");. Only one process can have a write lock on a file, so using this you can make sure that only one copy of your PHP script is running.

    Good Luck!

    0 讨论(0)
  • 2020-11-22 12:23

    You could start your php script from the command line (i.e. bash) by using

    nohup php myscript.php &

    the & puts your process in the background.

    Edit:
    Yes, there are some drawbacks, but not possible to control? That's just wrong.
    A simple kill processid will stop it. And it's still the best and simplest solution.

    0 讨论(0)
  • 2020-11-22 12:28

    Check out https://github.com/shaneharter/PHP-Daemon

    This is an object-oriented daemon library. It has built-in support for things like logging and error recovery, and it has support for creating background workers.

    0 讨论(0)
  • 2020-11-22 12:29

    Another option is to use Upstart. It was originally developed for Ubuntu (and comes packaged with it by default), but is intended to be suitable for all Linux distros.

    This approach is similar to Supervisord and daemontools, in that it automatically starts the daemon on system boot and respawns on script completion.

    How to set it up:

    Create a new script file at /etc/init/myphpworker.conf. Here is an example:

    # Info
    description "My PHP Worker"
    author      "Jonathan"
    
    # Events
    start on startup
    stop on shutdown
    
    # Automatically respawn
    respawn
    respawn limit 20 5
    
    # Run the script!
    # Note, in this example, if your PHP script returns
    # the string "ERROR", the daemon will stop itself.
    script
        [ $(exec /usr/bin/php -f /path/to/your/script.php) = 'ERROR' ] && ( stop; exit 1; )
    end script
    

    Starting & stopping your daemon:

    sudo service myphpworker start
    sudo service myphpworker stop
    

    Check if your daemon is running:

    sudo service myphpworker status
    

    Thanks

    A big thanks to Kevin van Zonneveld, where I learned this technique from.

    0 讨论(0)
  • 2020-11-22 12:32

    With new systemd you can create a service.

    You must create a file or a symlink in /etc/systemd/system/, eg. myphpdaemon.service and place content like this one, myphpdaemon will be the name of the service:

    [Unit]
    Description=My PHP Daemon Service
    #May your script needs MySQL or other services to run, eg. MySQL Memcached
    Requires=mysqld.service memcached.service 
    After=mysqld.service memcached.service
    
    [Service]
    User=root
    Type=simple
    TimeoutSec=0
    PIDFile=/var/run/myphpdaemon.pid
    ExecStart=/usr/bin/php -f /srv/www/myphpdaemon.php arg1 arg2> /dev/null 2>/dev/null
    #ExecStop=/bin/kill -HUP $MAINPID #It's the default you can change whats happens on stop command
    #ExecReload=/bin/kill -HUP $MAINPID
    KillMode=process
    
    Restart=on-failure
    RestartSec=42s
    
    StandardOutput=null #If you don't want to make toms of logs you can set it null if you sent a file or some other options it will send all php output to this one.
    StandardError=/var/log/myphpdaemon.log
    [Install]
    WantedBy=default.target
    

    You will be able to start, get status, restart and stop the services using the command

    systemctl <start|status|restart|stop|enable> myphpdaemon

    The PHP script should have a kind of "loop" to continue running.

    <?php
    gc_enable();//
    while (!connection_aborted() || PHP_SAPI == "cli") {
    
      //Code Logic
    
      //sleep and usleep could be useful
        if (PHP_SAPI == "cli") {
            if (rand(5, 100) % 5 == 0) {
                gc_collect_cycles(); //Forces collection of any existing garbage cycles
            }
        }
    }
    

    Working example:

    [Unit]
    Description=PHP APP Sync Service
    Requires=mysqld.service memcached.service
    After=mysqld.service memcached.service
    
    [Service]
    User=root
    Type=simple
    TimeoutSec=0
    PIDFile=/var/run/php_app_sync.pid
    ExecStart=/bin/sh -c '/usr/bin/php -f /var/www/app/private/server/cron/app_sync.php  2>&1 > /var/log/app_sync.log'
    KillMode=mixed
    
    Restart=on-failure
    RestartSec=42s
    
    [Install]
    WantedBy=default.target
    

    If your PHP routine should be executed once in a cycle (like a diggest) you may should use a shell or bash script to be invoked into systemd service file instead of PHP directly, for example:

    #!/usr/bin/env bash
    script_path="/app/services/"
    
    while [ : ]
    do
    #    clear
        php -f "$script_path"${1}".php" fixedparameter ${2}  > /dev/null 2>/dev/null
        sleep 1
    done
    

    If you chose these option you should change the KillMode to mixed to processes, bash(main) and PHP(child) be killed.

    ExecStart=/app/phpservice/runner.sh phpfile parameter  > /dev/null 2>/dev/null
    KillMode=process
    

    This method also is effective if you're facing a memory leak.

    Note: Every time that you change your "myphpdaemon.service" you must run `systemctl daemon-reload', but do worry if you not do, it will be alerted when is needed.

    0 讨论(0)
提交回复
热议问题