ProjeQtOr free project management software - How to Ensure ProjeQtOr Cron Process is Always Running - ProjeQtOr
 

How to Ensure ProjeQtOr Cron Process is Always Running

More
16 Sep 2019 18:10 - 16 Sep 2019 18:13 #1 by angeltek
ProjeQtOr uses a background PHP "cron" process that periodically performs various housekeeping functions such as generating alerts, automatically importing files & emails, etc. When a user logs into the application a check is made to see if this process is running and if not it is restarted. In theory it should then continue to run indefinitely. However there are circumstances when this alone is not sufficient to keep cron running - in particular:

  • If the request_terminate_timeout setting in /etc/php-fpm.conf (or in the /etc/php-fpm.d/ file for site) is non-zero and the site administrator is unable to change it (eg on a shared hosting server), then the cron process will be forcibly stopped after a relatively short time.
  • If the server or the server's php-fpm process is restarted (or ProjeQtOr's php process crashes), cron will again be forcibly stopped and will not restart until the next user login to the application, which on low usage sites may mean it is stopped for an extended time.
ProjeQtOr v8.2.0 introduces a mechanism (via API calls) for an external program to periodically check that the cron process is running and if not to restart it. Below are the steps need to get this working on a Linux server using the system's cron facility.

  1. Create a new ProjeQtOr user that will be dedicated to restarting cron via API calls. Do not make it a resource or a contact. Give it the "project guest" profile but do not assign it to any projects. Set a nice long strong password but don't bother to write it down because it will not be needed to make API calls (it just prevents unauthorised access via the normal application login).

  2. Enable http password protection on the site's 'projeqtor/api' directory. Copy the included '.htaccess.example' file to 'projeqtor/api/.htaccess' . Edit the new file changing the line 'AuthUserFile "./.htpasswd"' to point to the FULL path of where you want to store the .htpasswd file (this will contain the encrypted password for API access and ideally should be outside of the webserver's DocumentRoot directory tree - the example uses a relative path which usually expands to /etc/httpd/.htpasswd).

  3. Create an http username & password for the site's projeqtor/api directory. The http username MUST be the same as ProjeQtOr user you created in step 1. Use the command line utility ' htpasswd -c -B /path/to/.htpasswd {username}' where '{username}' is the ProjeQtOr username. You will be prompted to enter a long strong password which you will need to write down and then use in step 4.

  4. Create the script to restart cron via api calls. Copy & paste the following into a file and edit the site specific variables at the top as per instructions. Make sure this file is owned either by root or by the Linux user that will execute it as a cron job. Set the file permissions to allow it to be read and executed by this user only - remember that it contains a plain text username & password that can be used to make any api call including sensitive & destructive ones!

    #!/usr/bin/php
    <?php
     
    /*
     * Purpose:  Restart the cron process of a single ProjeQtOr application site.
     * Inputs:   None.
     * Outputs:  Prints for logging when a restart is initiated and if it fails.
     * Security: Ensure that this script file is only readable & writeable by root 
     *           and/or the specific Linux user that will be running this script!
     * Version:  1.0.0
     */
     
    /* ----------------------------------
     * ENTER SITE SPECIFIC VARIABLES HERE
     * ----------------------------------
     */
     
    /* Define the site's url with trailing slash (usually https://yourdomain/projeqtor/) */
    $siteUrl="https://yourdomain/projeqtor/";
     
    /* Define the ProjeQtOr API's httppass username & password */
    $httpUser="{username}";
    $httpPass="{password}";
     
    /* Define the maximum time in seconds allowed for the API call.
     * Required because the api call to start the cron process runs indefinitely.
     * Must be long enough to execute at peek loads, but not so long that it disturbs the system's cron.
     */
    $maxtime="10";
     
     
    /* ----------------------
     * DO NOT EDIT BELOW HERE
     * ----------------------
     */
     
     
    /* Perform an initial check to see if a restart is actually required */
    $fullUrl=$siteUrl."api/Cron/check";
    $api_response = callapi( $fullUrl, $httpUser, $httpPass, $maxtime );
    if ( preg_replace("#{.*:\"(.*)\"}.*#", "$1", $api_response) <> 'running' ) {
     
    	/* The cron process is not running, so attempt to start it */
    	echo "Info: Starting ProjeQtOr cron process for ".$siteUrl."\n";
    	$fullUrl=$siteUrl."api/Cron/start";
    	callapi( $fullUrl, $httpUser, $httpPass, $maxtime );
     
        /* Perform a final check to see if the restart was successful */
    	$fullUrl=$siteUrl."api/Cron/check";
    	$api_response = callapi( $fullUrl, $httpUser, $httpPass, $maxtime );
    	if ( preg_replace("#{.*:\"(.*)\"}.*#", "$1", $api_response) <> 'running' ) {
    		echo "Error: failed to start ProjeQtOr cron process\n";
    	}
    }
     
    /* ---------
     * Functions
     * ---------
     */
     
    /* Make an API call given:
     *  1) the full api url as a string
     *  2) the http username protecting the api directory as a string
     *  3) the http password protecting the api directory as a string
     *  4) the maximum time in seconds to allow for the call as a string
     * Returns the api's response as a string
     */
     
    function callapi( $url, $user, $pass, $time ) {
        $curl = curl_init($url);
    	curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
    	curl_setopt($curl, CURLOPT_USERPWD, $user.":".$pass);
    	curl_setopt($curl, CURLOPT_TIMEOUT, $time);
    	curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    	curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    	curl_setopt($curl, CURLOPT_FAILONERROR, true);
    	$curl_response = curl_exec($curl);
    	curl_close($curl);
    	return $curl_response;
    }
    ?>

  5. Test that the script works by executing it first as root and then as the user that will run the cron job (if not root). It should:
    • return quickly and produce no output if ProjeQtOr's cron process is already running (see the Administration section of the application),
    • pause for 10 seconds then only output "Info: Starting ProjeQtOr cron process" if ProjeQtOr's cron process was not running and was successfully restarted,
    • also print "Error: failed to start ProjeQtOr cron process" if there was a problem.

  6. Create a Linux cron job to execute the script on a regular basis. For simplicity move the script file (or create a symlink to it) in to '/etc/cron.hourly' to have Linux cron execute the script every hour. Alternatively use 'crontab' (or hand edit a file in /etc/cron.d) to execute the script on a custom schedule.
Last edit: 16 Sep 2019 18:13 by angeltek.
The following user(s) said Thank You: babynus

Please Log in or Create an account to join the conversation.

Moderators: babynusprotion
Time to create page: 0.060 seconds