- Compatible XF Versions
- 2.2
- 2.3
This XenForo 2.x addon implements an advanced CLI triggered job runner for use with Unix cron as a replacement for the built-in
The command is called
Features
Main features of this addon:
Requirements
This addon requires PHP 7.0 or higher and has been tested on XenForo v2.2 and v2.3
Installation
Install as per normal addon installation.
Once installed, go to the System and performance options page as change the Job run trigger setting to "Server based trigger"
First, you should test that your job runner is functioning - execute the following command from your CLI:
For example, if your forum root is /srv/www/xenforo/community, then the job runner command would be:
Running this command will execute any outstanding jobs and then finish with a message about whether there are more jobs waiting to be executed or not. When executing this command from cron, it is recommended that you use the
Once you are happy that the job runner functions correctly, you will need to create your own cron task to run it on a schedule of your choosing.
NOTE: if you already have a cron task set up to run
Approach #1 using crontab:
It is highly recommended that you have your cron task run as the web server user to prevent potential permission problems.
For example, on Ubuntu with a web server user of www-data, install a cron task by running the following command:
Edit the crontab file and add:
Save the crontab.
Approach #2 using cron.d:
Instead of using a crontab, some Linux distributions create a well-known directory which is automatically checked for cron tasks to execute. In the case of Ubuntu, you can create files in
Create a file in
... where
Again, using our previous example where web server user is
Both options (crontab and cron.d) will execute the job runner every minute, checking for outstanding jobs to be run.
By default, the job runner will run for a maximum of 30 seconds, executing any outstanding jobs until there are no more runnable jobs in the queue.
Upgrading from addon v1.x after upgrading XenForo to v2.2
v2.0 of this addon changes the command name and the maximum permitted run time. Note also that the
To upgrade:
Configuration
You may adjust the maximum execution time of the job runner by specifying the --max-execution-time=[TIME] option on the command line.
For example, to allow the job runner to execute for a maximum of 45 seconds:
This addon uses lock files to prevent multiple job runner commands to execute at the same time, which also allows us to have the command run for longer periods on busy sites.
The maximum execution time allowed is 10 minutes (600 seconds). The command will execute until it finds no more outstanding jobs and then stop - so execution time is typically only a few seconds.
For further customisation of your job execution, you may also adjust the maximum time that each job is permitted to run.
This is configured via a XenForo config.php Option:
The
In general it is suggested that this setting be kept to a relatively small value to avoid the situation where a single very long job may prevent other jobs from executing in a timely manner. Some experimentation may be required to find the optimal value for your server load and forum size. If in doubt, leave it as the default setting of 8 seconds.
Usage
The
Show Jobs
The
By default only the next scheduled 100 jobs will be shown, you may use the --all option to show a complete list of all pending jobs.
There should always be at least two jobs showing: the main Cron job and the Upgrade Check job.
Debugging Jobs
There are extensive debugging tools to help identify issues with Jobs and Cron tasks.
To run in debug mode, first disable the Unix cron which runs jobs automatically (don't forget to turn it back on again once you are finished debugging!) and then use the verbosity options (Verbose:
Output is to the console and is in a format similar to that used by the Monolog library (although we do not use Monolog to generate the output).
For example, Verbose option
The Very Verbose option -vv adds context, typically about the JobResult:
And finally the Debug option -vvv adds extra information about the job:
Custom job debugging
You can add additional debugging to your custom jobs.
Add the following function to your job class to call the logJobProgress function of our Logger class:
Then you can call the log() function in your job code to send information to the console when the Job Runner is executed in verbose mode.
For example - see the test job included in this addon Hampel\JobRunner\Job\TestJob:
The above code will generate the following output when the Job Runner is in debug mode:
No output will be shown when run in quiet mode - and more importantly, if this addon is disabled the logging code will not need to be removed. The important part is the if (!isset(\XF::app['cli.logger'])) return; line, which will abort if our Logger is not available.
Custom Cron task debugging
Using a similar mechanism, we can add debugging code to our custom Cron tasks too:
Add a slightly different function to your Cron tasks to call the log() function of our Logger class:
Then, simply call something like: self::log("some message about something happening", ['key' => 'value']); within your code to output information to the console when the Job Runner is executed in verbose mode.
Logger Trait
There is also a trait you can include in your classes: Hampel\JobRunner\Cli\LoggerTrait which implements some basic logging functions you may call from your code:
Debugging Cron tasks
As of v2.0 beta 3, there are two new commands for working with XF cron tasks:
Show Crons
The hg:show-crons command will list all of your active XF cron tasks
Bash:
$ cmd.php hg:show-crons<br><br><span>19</span> active <span>cron</span> entries found<br><br>+---------------------------+----------------------+--------------------------+<br><span>|</span> ID <span>|</span> Next Run <span>(</span>UTC+10:00<span>)</span> <span>|</span> Addon <span>|</span><br>+---------------------------+----------------------+--------------------------+<br><span>|</span> forumStatistics <span>|</span> <span>29</span>-Sep-2020 06:53 <span>|</span> XF <span>|</span><br><span>|</span> emailBounce <span>|</span> <span>29</span>-Sep-2020 06:53 <span>|</span> XF <span>|</span><br><span>|</span> warningExpiry <span>|</span> <span>29</span>-Sep-2020 06:55 <span>|</span> XF <span>|</span><br><span>|</span> rebuildSearchForumCache <span>|</span> <span>29</span>-Sep-2020 07:00 <span>|</span> XF <span>|</span><br><span>|</span> memberStatsCache <span>|</span> <span>29</span>-Sep-2020 07:00 <span>|</span> XF <span>|</span><br><span>|</span> feeder <span>|</span> <span>29</span>-Sep-2020 07:02 <span>|</span> XF <span>|</span><br><span>|</span> cleanUpHourly <span>|</span> <span>29</span>-Sep-2020 07:10 <span>|</span> XF <span>|</span><br><span>|</span> emailUnsubscribe <span>|</span> <span>29</span>-Sep-2020 07:13 <span>|</span> XF <span>|</span><br><span>|</span> userGroupPromotions <span>|</span> <span>29</span>-Sep-2020 07:20 <span>|</span> XF <span>|</span><br><span>|</span> views <span>|</span> <span>29</span>-Sep-2020 07:30 <span>|</span> XF <span>|</span><br><span>|</span> trophy <span>|</span> <span>29</span>-Sep-2020 07:40 <span>|</span> XF <span>|</span><br><span>|</span> expireTempUserChanges <span>|</span> <span>29</span>-Sep-2020 07:42 <span>|</span> XF <span>|</span><br><span>|</span> deleteExpiredBans <span>|</span> <span>29</span>-Sep-2020 07:45 <span>|</span> XF <span>|</span><br><span>|</span> downgradeExpired <span>|</span> <span>29</span>-Sep-2020 07:50 <span>|</span> XF <span>|</span><br><span>|</span> fileCheck <span>|</span> <span>29</span>-Sep-2020 <span>10</span>:10 <span>|</span> XF <span>|</span><br><span>|</span> dailyStats <span>|</span> <span>29</span>-Sep-2020 <span>10</span>:30 <span>|</span> XF <span>|</span><br><span>|</span> cleanUpDaily <span>|</span> <span>29</span>-Sep-2020 <span>13</span>:00 <span>|</span> XF <span>|</span><br><span>|</span> activitySummaryEmail <span>|</span> <span>30</span>-Sep-2020 00:20 <span>|</span> XF <span>|</span><br><span>|</span> sitemap <span>|</span> <span>30</span>-Sep-2020 <span>15</span>:37 <span>|</span> XF <span>|</span><br>+---------------------------+----------------------+--------------------------+<br><br>The current <span>time</span> is: <span>29</span>-Sep-2020 06:52:05 <span>(</span>UTC+10:00<span>)</span>
There are three command line options you can specify:
Run Cron
The hg:run-cron command will execute an XF cron task - simply specify a cron ID as the argument.
For example: cmd.php hg:run-cron activitySummaryEmail will run the "Send activity summary email" cron task.
By default, disabled cron tasks cannot be run - so you can override this by specifying the -f or --force option on the command line.
The same verbosity flags work here - so specify -v, -vv or -vvv to generate the desired level of output.
xf:run-jobs
command introduced in XF 2.2The command is called
hg:run-jobs
and does the same thing that xf:run-jobs
does, but with more options and functionality.Features
Main features of this addon:
- allows commands to process jobs/crons for up to 10 minutes at a time, even when triggered every minute from a cron task (uses a lock file to prevent multiple executions in parallel) - ideal for improving job performance on high traffic sites
- extensive debugging output available for testing and identifying issues with jobs and cron tasks
- drop-in replacement for
xf:run-jobs
- command to list all outstanding Jobs
hg:show-jobs
- command to list all XF Cron tasks
hg:show-crons
- command to execute an XF Cron task
hg:run-cron
Requirements
This addon requires PHP 7.0 or higher and has been tested on XenForo v2.2 and v2.3
Installation
Install as per normal addon installation.
Once installed, go to the System and performance options page as change the Job run trigger setting to "Server based trigger"
First, you should test that your job runner is functioning - execute the following command from your CLI:
Bash:
$ php <span><</span>path to your forum root<span>></span>/cmd.php hg:run-jobs
For example, if your forum root is /srv/www/xenforo/community, then the job runner command would be:
Bash:
$ php /srv/www/xenforo/community/cmd.php hg:run-jobs
Running this command will execute any outstanding jobs and then finish with a message about whether there are more jobs waiting to be executed or not. When executing this command from cron, it is recommended that you use the
--quiet
(or -q
) flag to suppress output.Once you are happy that the job runner functions correctly, you will need to create your own cron task to run it on a schedule of your choosing.
NOTE: if you already have a cron task set up to run
xf:run-jobs
simply disable that and replace it with an identical task which runs hg:run-jobs
instead.Approach #1 using crontab:
It is highly recommended that you have your cron task run as the web server user to prevent potential permission problems.
For example, on Ubuntu with a web server user of www-data, install a cron task by running the following command:
Bash:
$ <span>sudo</span> <span>crontab</span> -u www-data -e
Edit the crontab file and add:
Bash:
* * * * * php /path/to/your/forum/root/cmd.php --quiet hg:run-jobs
Save the crontab.
Approach #2 using cron.d:
Instead of using a crontab, some Linux distributions create a well-known directory which is automatically checked for cron tasks to execute. In the case of Ubuntu, you can create files in
/etc/cron.d/
where you specify the schedule, the user to execute the command as, and the command itself.Create a file in
/etc/cron.d/
with the following contents:
Bash:
* * * * * webserver-user php /path/to/your/forum/root/cmd.php --quiet hg:run-jobs
... where
webserver-user
is changed to the name of the user your web server runs as and change the path to your forum root.Again, using our previous example where web server user is
www-data
and our forum root is/srv/www/xenforo/community
, I would execute the following command to create the cron file:
Bash:
<span>echo</span> <span>"* * * * * www-data php /srv/www/xenforo/community/cmd.php --quiet hg:run-jobs"</span> <span>|</span> <span>sudo</span> <span>tee</span> -a /etc/cron.d/xenforo
Both options (crontab and cron.d) will execute the job runner every minute, checking for outstanding jobs to be run.
By default, the job runner will run for a maximum of 30 seconds, executing any outstanding jobs until there are no more runnable jobs in the queue.
Upgrading from addon v1.x after upgrading XenForo to v2.2
v2.0 of this addon changes the command name and the maximum permitted run time. Note also that the
--time
option in v1.x has been renamed to --max-execution-time
in line with the core job runner provided in XF v2.2.To upgrade:
- Upgrade to XF v2.2 RC2 or later
- Install v2.0.x of the addon
- change your unix cron entry to execute
hg:run-jobs
instead ofxf:run-jobs
- if you use the
--time
option, rename this to--max-execution-time
- optional: adjust the
--max-execution-time
option to anything up to 600 seconds (10 minutes) to allow job processing to take as long as it needs. For example:--max-execution-time=180
will allow the Job Runner to execute for up to 3 minutes at a time
Configuration
You may adjust the maximum execution time of the job runner by specifying the --max-execution-time=[TIME] option on the command line.
For example, to allow the job runner to execute for a maximum of 45 seconds:
Bash:
$ php <span><</span>path to your forum root<span>></span>/cmd.php --max-execution-time<span>=</span><span>45</span> hg:run-jobs
This addon uses lock files to prevent multiple job runner commands to execute at the same time, which also allows us to have the command run for longer periods on busy sites.
The maximum execution time allowed is 10 minutes (600 seconds). The command will execute until it finds no more outstanding jobs and then stop - so execution time is typically only a few seconds.
For further customisation of your job execution, you may also adjust the maximum time that each job is permitted to run.
This is configured via a XenForo config.php Option:
PHP:
<span>$config</span><span>[</span><span>'jobMaxRunTime'</span><span>]</span> <span>=</span> <span>8</span><span>;</span>
The
jobMaxRunTime
option configures the amount of time in seconds that processing jobs will be allowed to run before they are suspended for further processing on another go-around, if possible. The default setting is optimised for the browser-triggered job runner and so to allow jobs to execute longer in a CLI environment, you may want to adjust this to a higher value.In general it is suggested that this setting be kept to a relatively small value to avoid the situation where a single very long job may prevent other jobs from executing in a timely manner. Some experimentation may be required to find the optimal value for your server load and forum size. If in doubt, leave it as the default setting of 8 seconds.
Usage
The
run-jobs
command should be executed automatically using a cron task as per the instructions above.Show Jobs
The
hg:show-jobs
command outputs a list of all the currently pending jobs, so you can see how full the jobs queue is.By default only the next scheduled 100 jobs will be shown, you may use the --all option to show a complete list of all pending jobs.
There should always be at least two jobs showing: the main Cron job and the Upgrade Check job.
Bash:
$ php cmd.php xf:show-jobs <br><br><span>2</span> pending <span>jobs</span> found<br><br>+----------------+-----------------+----------------------+----------------------+<br><span>|</span> Key <span>|</span> Class <span>|</span> Next Run <span>|</span> Last Run <span>|</span><br>+----------------+-----------------+----------------------+----------------------+<br><span>|</span> <span>cron</span> <span>|</span> XF<span>\</span>Job<span>\</span>Cron <span>|</span> <span>11</span>-Apr-2019 <span>10</span>:52:01 <span>|</span> <span>11</span>-Apr-2019 <span>10</span>:52:31 <span>|</span><br><span>|</span> xfUpgradeCheck <span>|</span> XF:UpgradeCheck <span>|</span> <span>12</span>-Apr-2019 00:12:21 <span>|</span> <span>10</span>-Apr-2019 <span>21</span>:24:03 <span>|</span><br>+----------------+-----------------+----------------------+----------------------+<br><br>The current <span>time</span> is: <span>11</span>-Apr-2019 <span>10</span>:52:31 <span>(</span>UTC+10:00<span>)</span>
Debugging Jobs
There are extensive debugging tools to help identify issues with Jobs and Cron tasks.
To run in debug mode, first disable the Unix cron which runs jobs automatically (don't forget to turn it back on again once you are finished debugging!) and then use the verbosity options (Verbose:
-v
, Very verbose: -vv
or Debug: -vvv
) for the hg:run-jobs
command to specify the level of output to show on the console.Output is to the console and is in a format similar to that used by the Monolog library (although we do not use Monolog to generate the output).
For example, Verbose option
-v
:
Bash:
$ php cmd.php hg:run-jobs -v<br><span>[</span><span>2019</span>-11-27 <span>23</span>:53:09<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XF<span>\</span>Cron<span>\</span>CleanUp::runUserDowngrade executed <span>in</span> <span>0.01</span> seconds<br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:53:09<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry Hampel<span>\</span>LogDigest<span>\</span>Cron<span>\</span>SendLogs::serverError executed <span>in</span> <span>0.00</span> seconds<br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:53:09<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XF<span>\</span>Cron<span>\</span>MemberStats::rebuildMemberStatsCache executed <span>in</span> <span>0.00</span> seconds<br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:53:09<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry Hampel<span>\</span>Slack<span>\</span>Cron<span>\</span>NotifyLogs::notify executed <span>in</span> <span>0.03</span> seconds<br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:53:09<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XF<span>\</span>Cron<span>\</span>Feeder::importFeeds executed <span>in</span> <span>0.01</span> seconds<br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:53:09<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XFMG<span>\</span>Cron<span>\</span>RandomCache::generateRandomMediaCache executed <span>in</span> <span>0.07</span> seconds<br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:53:09<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XF<span>\</span>Cron<span>\</span>EmailBounce::process executed <span>in</span> <span>0.00</span> seconds<br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:53:09<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XF<span>\</span>Cron<span>\</span>Counters::rebuildForumStatistics executed <span>in</span> <span>0.02</span> seconds<br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:53:09<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Job executed <span>in</span> <span>0.20</span> seconds<br><br>No <span>more</span> runnable <span>jobs</span> pending
The Very Verbose option -vv adds context, typically about the JobResult:
Bash:
$ php cmd.php hg:run-jobs -vv<br><span>[</span><span>2019</span>-11-27 <span>23</span>:49:49<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry Hampel<span>\</span>Slack<span>\</span>Cron<span>\</span>NotifyLogs::notify executed <span>in</span> <span>0.01</span> seconds <span>{</span><span>"entry_id"</span><span>:</span><span>"slackNotifyServerErrors"</span>,<span>"cron_class"</span><span>:</span><span>"Hampel<span title="\\">\\</span>Slack<span title="\\">\\</span>Cron<span title="\\">\\</span>NotifyLogs"</span>,<span>"cron_method"</span><span>:</span><span>"notify"</span>,<span>"run_rules"</span>:<span>{</span><span>"day_type"</span><span>:</span><span>"dom"</span>,<span>"dom"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"hours"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"minutes"</span>:<span>{</span><span>"0"</span>:-1<span>}</span><span>}</span>,<span>"active"</span>:true,<span>"next_run"</span>:1574898543,<span>"addon_id"</span><span>:</span><span>"Hampel\/Slack"</span><span>}</span><br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:49:49<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry Hampel<span>\</span>SparkPost<span>\</span>Cron<span>\</span>MessageEvents::fetchMessageEvents executed <span>in</span> <span>0.00</span> seconds <span>{</span><span>"entry_id"</span><span>:</span><span>"sparkpostMessageEvents"</span>,<span>"cron_class"</span><span>:</span><span>"Hampel<span title="\\">\\</span>SparkPost<span title="\\">\\</span>Cron<span title="\\">\\</span>MessageEvents"</span>,<span>"cron_method"</span><span>:</span><span>"fetchMessageEvents"</span>,<span>"run_rules"</span>:<span>{</span><span>"day_type"</span><span>:</span><span>"dom"</span>,<span>"dom"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"hours"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"minutes"</span>:<span>{</span><span>"0"</span>:19,<span>"1"</span>:49<span>}</span><span>}</span>,<span>"active"</span>:true,<span>"next_run"</span>:1574898543,<span>"addon_id"</span><span>:</span><span>"Hampel\/SparkPost"</span><span>}</span><br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:49:49<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Job executed <span>in</span> <span>0.03</span> seconds <span>{</span><span>"completed"</span>:false,<span>"jobId"</span>:2,<span>"continueDate"</span>:1574898603,<span>"continueDate_formatted"</span><span>:</span><span>"2019-11-27 23:50:03 UTC"</span>,<span>"statusMessage"</span><span>:</span><span>"Running... Cron entries"</span><span>}</span><br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:49:49<span>]</span> Hampel<span>\</span>SparkPost:MessageEvent: Job executed <span>in</span> <span>0.83</span> seconds <span>{</span><span>"completed"</span>:true,<span>"jobId"</span>:12,<span>"continueDate"</span>:null,<span>"continueDate_formatted"</span><span>:</span><span>""</span>,<span>"statusMessage"</span><span>:</span><span>""</span><span>}</span><br><br>No <span>more</span> runnable <span>jobs</span> pending
And finally the Debug option -vvv adds extra information about the job:
Bash:
$ php cmd.php hg:run-jobs -vvv<br><span>[</span><span>2019</span>-11-27 <span>23</span>:48:03<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XF<span>\</span>Cron<span>\</span>Feeder::importFeeds executed <span>in</span> <span>0.01</span> seconds <span>{</span><span>"entry_id"</span><span>:</span><span>"feeder"</span>,<span>"cron_class"</span><span>:</span><span>"XF<span title="\\">\\</span>Cron<span title="\\">\\</span>Feeder"</span>,<span>"cron_method"</span><span>:</span><span>"importFeeds"</span>,<span>"run_rules"</span>:<span>{</span><span>"day_type"</span><span>:</span><span>"dom"</span>,<span>"dom"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"hours"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"minutes"</span>:<span>{</span><span>"0"</span>:2,<span>"1"</span>:12,<span>"2"</span>:22,<span>"3"</span>:32,<span>"4"</span>:42,<span>"5"</span>:52<span>}</span><span>}</span>,<span>"active"</span>:true,<span>"next_run"</span>:1574879524,<span>"addon_id"</span><span>:</span><span>"XF"</span><span>}</span> <span>{</span><span>}</span><br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:48:03<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XF<span>\</span>Cron<span>\</span>Counters::rebuildForumStatistics executed <span>in</span> <span>0.02</span> seconds <span>{</span><span>"entry_id"</span><span>:</span><span>"forumStatistics"</span>,<span>"cron_class"</span><span>:</span><span>"XF<span title="\\">\\</span>Cron<span title="\\">\\</span>Counters"</span>,<span>"cron_method"</span><span>:</span><span>"rebuildForumStatistics"</span>,<span>"run_rules"</span>:<span>{</span><span>"day_type"</span><span>:</span><span>"dom"</span>,<span>"dom"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"hours"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"minutes"</span>:<span>{</span><span>"0"</span>:3,<span>"1"</span>:13,<span>"2"</span>:23,<span>"3"</span>:33,<span>"4"</span>:43,<span>"5"</span>:53<span>}</span><span>}</span>,<span>"active"</span>:true,<span>"next_run"</span>:1574879584,<span>"addon_id"</span><span>:</span><span>"XF"</span><span>}</span> <span>{</span><span>}</span><br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:48:03<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XF<span>\</span>Cron<span>\</span>MemberStats::rebuildMemberStatsCache executed <span>in</span> <span>0.03</span> seconds <span>{</span><span>"entry_id"</span><span>:</span><span>"memberStatsCache"</span>,<span>"cron_class"</span><span>:</span><span>"XF<span title="\\">\\</span>Cron<span title="\\">\\</span>MemberStats"</span>,<span>"cron_method"</span><span>:</span><span>"rebuildMemberStatsCache"</span>,<span>"run_rules"</span>:<span>{</span><span>"day_type"</span><span>:</span><span>"dom"</span>,<span>"dom"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"hours"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"minutes"</span>:<span>{</span><span>"0"</span>:0,<span>"1"</span>:10,<span>"2"</span>:20,<span>"3"</span>:30,<span>"4"</span>:40,<span>"5"</span>:50<span>}</span><span>}</span>,<span>"active"</span>:true,<span>"next_run"</span>:1574880004,<span>"addon_id"</span><span>:</span><span>"XF"</span><span>}</span> <span>{</span><span>}</span><br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:48:03<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XF<span>\</span>Cron<span>\</span>Trophy::runTrophyCheck executed <span>in</span> <span>0.00</span> seconds <span>{</span><span>"entry_id"</span><span>:</span><span>"trophy"</span>,<span>"cron_class"</span><span>:</span><span>"XF<span title="\\">\\</span>Cron<span title="\\">\\</span>Trophy"</span>,<span>"cron_method"</span><span>:</span><span>"runTrophyCheck"</span>,<span>"run_rules"</span>:<span>{</span><span>"day_type"</span><span>:</span><span>"dom"</span>,<span>"dom"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"hours"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"minutes"</span>:<span>{</span><span>"0"</span>:40<span>}</span><span>}</span>,<span>"active"</span>:true,<span>"next_run"</span>:1574880004,<span>"addon_id"</span><span>:</span><span>"XF"</span><span>}</span> <span>{</span><span>}</span><br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:48:03<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XFMG<span>\</span>Cron<span>\</span>Statistics::cacheGalleryStatistics executed <span>in</span> <span>0.01</span> seconds <span>{</span><span>"entry_id"</span><span>:</span><span>"xfmgCacheStats"</span>,<span>"cron_class"</span><span>:</span><span>"XFMG<span title="\\">\\</span>Cron<span title="\\">\\</span>Statistics"</span>,<span>"cron_method"</span><span>:</span><span>"cacheGalleryStatistics"</span>,<span>"run_rules"</span>:<span>{</span><span>"day_type"</span><span>:</span><span>"dom"</span>,<span>"dom"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"hours"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"minutes"</span>:<span>{</span><span>"0"</span>:10,<span>"1"</span>:40<span>}</span><span>}</span>,<span>"active"</span>:true,<span>"next_run"</span>:1574880004,<span>"addon_id"</span><span>:</span><span>"XFMG"</span><span>}</span> <span>{</span><span>}</span><br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:48:03<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XF<span>\</span>Cron<span>\</span>CleanUp::expireTempUserChanges executed <span>in</span> <span>0.00</span> seconds <span>{</span><span>"entry_id"</span><span>:</span><span>"expireTempUserChanges"</span>,<span>"cron_class"</span><span>:</span><span>"XF<span title="\\">\\</span>Cron<span title="\\">\\</span>CleanUp"</span>,<span>"cron_method"</span><span>:</span><span>"expireTempUserChanges"</span>,<span>"run_rules"</span>:<span>{</span><span>"day_type"</span><span>:</span><span>"dom"</span>,<span>"dom"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"hours"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"minutes"</span>:<span>{</span><span>"0"</span>:42<span>}</span><span>}</span>,<span>"active"</span>:true,<span>"next_run"</span>:1574880124,<span>"addon_id"</span><span>:</span><span>"XF"</span><span>}</span> <span>{</span><span>}</span><br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:48:03<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XFMG<span>\</span>Cron<span>\</span>RandomCache::generateRandomAlbumCache executed <span>in</span> <span>0.02</span> seconds <span>{</span><span>"entry_id"</span><span>:</span><span>"xfmgGenerateRandomAlbum"</span>,<span>"cron_class"</span><span>:</span><span>"XFMG<span title="\\">\\</span>Cron<span title="\\">\\</span>RandomCache"</span>,<span>"cron_method"</span><span>:</span><span>"generateRandomAlbumCache"</span>,<span>"run_rules"</span>:<span>{</span><span>"day_type"</span><span>:</span><span>"dom"</span>,<span>"dom"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"hours"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"minutes"</span>:<span>{</span><span>"0"</span>:12,<span>"1"</span>:42<span>}</span><span>}</span>,<span>"active"</span>:true,<span>"next_run"</span>:1574880124,<span>"addon_id"</span><span>:</span><span>"XFMG"</span><span>}</span> <span>{</span><span>}</span><br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:48:03<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XF<span>\</span>Cron<span>\</span>EmailUnsubscribe::process executed <span>in</span> <span>0.00</span> seconds <span>{</span><span>"entry_id"</span><span>:</span><span>"emailUnsubscribe"</span>,<span>"cron_class"</span><span>:</span><span>"XF<span title="\\">\\</span>Cron<span title="\\">\\</span>EmailUnsubscribe"</span>,<span>"cron_method"</span><span>:</span><span>"process"</span>,<span>"run_rules"</span>:<span>{</span><span>"day_type"</span><span>:</span><span>"dom"</span>,<span>"dom"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"hours"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"minutes"</span>:<span>{</span><span>"0"</span>:13,<span>"1"</span>:43<span>}</span><span>}</span>,<span>"active"</span>:true,<span>"next_run"</span>:1574880184,<span>"addon_id"</span><span>:</span><span>"XF"</span><span>}</span> <span>{</span><span>}</span><br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:48:03<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Cron entry XF<span>\</span>Cron<span>\</span>Ban::deleteExpiredBans executed <span>in</span> <span>0.01</span> seconds <span>{</span><span>"entry_id"</span><span>:</span><span>"deleteExpiredBans"</span>,<span>"cron_class"</span><span>:</span><span>"XF<span title="\\">\\</span>Cron<span title="\\">\\</span>Ban"</span>,<span>"cron_method"</span><span>:</span><span>"deleteExpiredBans"</span>,<span>"run_rules"</span>:<span>{</span><span>"day_type"</span><span>:</span><span>"dom"</span>,<span>"dom"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"hours"</span>:<span>{</span><span>"0"</span>:-1<span>}</span>,<span>"minutes"</span>:<span>{</span><span>"0"</span>:45<span>}</span><span>}</span>,<span>"active"</span>:true,<span>"next_run"</span>:1574880304,<span>"addon_id"</span><span>:</span><span>"XF"</span><span>}</span> <span>{</span><span>}</span><br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:48:03<span>]</span> XF<span>\</span>Job<span>\</span>Cron: Job executed <span>in</span> <span>0.32</span> seconds <span>{</span><span>"completed"</span>:false,<span>"jobId"</span>:2,<span>"continueDate"</span>:1574898543,<span>"continueDate_formatted"</span><span>:</span><span>"2019-11-27 23:49:03 UTC"</span>,<span>"statusMessage"</span><span>:</span><span>"Running... Cron entries"</span><span>}</span> <span>{</span><span>"job_id"</span>:2,<span>"unique_key"</span><span>:</span><span>"cron"</span>,<span>"execute_class"</span><span>:</span><span>"XF<span title="\\">\\</span>Job<span title="\\">\\</span>Cron"</span>,<span>"execute_data"</span>:<span>{</span><span>}</span>,<span>"manual_execute"</span>:0,<span>"trigger_date"</span>:1574879464,<span>"last_run_date"</span>:1574879405,<span>"trigger_date_formatted"</span><span>:</span><span>"2019-11-27 18:31:04 UTC"</span>,<span>"last_run_date_formatted"</span><span>:</span><span>"2019-11-27 18:30:05 UTC"</span><span>}</span><br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:48:03<span>]</span> Hampel<span>\</span>SparkPost:MessageEvent: Job executed <span>in</span> <span>0.90</span> seconds <span>{</span><span>"completed"</span>:true,<span>"jobId"</span>:10,<span>"continueDate"</span>:null,<span>"continueDate_formatted"</span><span>:</span><span>""</span>,<span>"statusMessage"</span><span>:</span><span>""</span><span>}</span> <span>{</span><span>"job_id"</span>:10,<span>"unique_key"</span><span>:</span><span>"SparkPostMessageEvents"</span>,<span>"execute_class"</span><span>:</span><span>"Hampel<span title="\\">\\</span>SparkPost:MessageEvent"</span>,<span>"execute_data"</span>:<span>{</span><span>}</span>,<span>"manual_execute"</span>:0,<span>"trigger_date"</span>:1574898483,<span>"last_run_date"</span>:null,<span>"trigger_date_formatted"</span><span>:</span><span>"2019-11-27 23:48:03 UTC"</span>,<span>"last_run_date_formatted"</span><span>:</span><span>""</span><span>}</span><br><br><span>[</span><span>2019</span>-11-27 <span>23</span>:48:03<span>]</span> Hampel<span>\</span>SparkPost:EmailBounce: Job executed <span>in</span> <span>0.02</span> seconds <span>{</span><span>"completed"</span>:true,<span>"jobId"</span>:11,<span>"continueDate"</span>:null,<span>"continueDate_formatted"</span><span>:</span><span>""</span>,<span>"statusMessage"</span><span>:</span><span>""</span><span>}</span> <span>{</span><span>"job_id"</span>:11,<span>"unique_key"</span><span>:</span><span>"SparkPostEmailBounce"</span>,<span>"execute_class"</span><span>:</span><span>"Hampel<span title="\\">\\</span>SparkPost:EmailBounce"</span>,<span>"execute_data"</span>:<span>{</span><span>}</span>,<span>"manual_execute"</span>:0,<span>"trigger_date"</span>:1574898483,<span>"last_run_date"</span>:null,<span>"trigger_date_formatted"</span><span>:</span><span>"2019-11-27 23:48:03 UTC"</span>,<span>"last_run_date_formatted"</span><span>:</span><span>""</span><span>}</span><br><br>No <span>more</span> runnable <span>jobs</span> pending
Custom job debugging
You can add additional debugging to your custom jobs.
Add the following function to your job class to call the logJobProgress function of our Logger class:
PHP:
<span>protected</span> <span>function</span> <span>log</span><span>(</span><span>$message</span><span>,</span> <span>array</span> <span>$context</span> <span>=</span> <span>[</span><span>]</span><span>)</span><br> <span>{</span><br> <span>// check to see if we actually have a logger available and abort if not</span><br> <span>if</span> <span>(</span><span>!</span><span>isset</span><span>(</span><span>$this</span><span>-</span><span>></span><span>app</span><span>[</span><span>'cli.logger'</span><span>]</span><span>)</span><span>)</span> <span>return</span><span>;</span><br><br> <span>/** @var Logger $logger */</span><br> <span>$logger</span> <span>=</span> <span>$this</span><span>-</span><span>></span><span>app</span><span>[</span><span>'cli.logger'</span><span>]</span><span>;</span><br> <span>$logger</span><span>-</span><span>></span><span>logJobProgress</span><span>(</span><span>$message</span><span>,</span> <span>$context</span><span>,</span> <span>$this</span><span>)</span><span>;</span><br> <span>}</span>
Then you can call the log() function in your job code to send information to the console when the Job Runner is executed in verbose mode.
For example - see the test job included in this addon Hampel\JobRunner\Job\TestJob:
PHP:
<span>public</span> <span>function</span> <span>run</span><span>(</span><span>$maxRunTime</span><span>)</span><br> <span>{</span><br> <span>$this</span><span>-</span><span>></span><span>log</span><span>(</span><span>"About to start test job"</span><span>,</span> <span>$this</span><span>-</span><span>></span><span>data</span><span>)</span><span>;</span><br><br> <span>$mail</span> <span>=</span> <span>$this</span><span>-</span><span>></span><span>app</span><span>-</span><span>></span><span>mailer</span><span>(</span><span>)</span><span>-</span><span>></span><span>newMail</span><span>(</span><span>)</span><span>;</span><br> <span>$mail</span><span>-</span><span>></span><span>setTo</span><span>(</span><span>$this</span><span>-</span><span>></span><span>data</span><span>[</span><span>'email'</span><span>]</span><span>)</span><span>;</span><br> <span>$mail</span><span>-</span><span>></span><span>setContent</span><span>(</span><br> <span>"Test job"</span><span>,</span><br> <span>"This is an email sent from a test job"</span><br> <span>)</span><span>;</span><br> <span>$sent</span> <span>=</span> <span>$mail</span><span>-</span><span>></span><span>send</span><span>(</span><span>)</span><span>;</span><br><br> <span>$this</span><span>-</span><span>></span><span>log</span><span>(</span><span>"Sent mail"</span><span>,</span> <span>[</span><span>'sent'</span> <span>=</span><span>></span> <span>$sent</span><span>]</span><span>)</span><span>;</span><br><br> <span>return</span> <span>$this</span><span>-</span><span>></span><span>complete</span><span>(</span><span>)</span><span>;</span><br> <span>}</span>
The above code will generate the following output when the Job Runner is in debug mode:
Bash:
$ php cmd.php hg:run-jobs -vvv<br><span>[</span><span>2019</span>-11-28 00:26:21<span>]</span> Hampel<span>\</span>JobRunner:TestJob: About to start <span>test</span> job <span>{</span><span>"email"</span><span>:</span><span>"[email protected]"</span><span>}</span> <span>{</span><span>"job_id"</span>:17,<span>"class"</span><span>:</span><span>"Hampel<span title="\\">\\</span>JobRunner<span title="\\">\\</span>Job<span title="\\">\\</span>TestJob"</span>,<span>"status_message"</span><span>:</span><span>"Testing jobs"</span>,<span>"data"</span>:<span>{</span><span>"email"</span><span>:</span><span>"[email protected]"</span><span>}</span>,<span>"execution_time"</span><span>:</span><span>"0.00"</span><span>}</span><br><br><span>[</span><span>2019</span>-11-28 00:26:21<span>]</span> Hampel<span>\</span>JobRunner:TestJob: Sent mail <span>{</span><span>"sent"</span>:1<span>}</span> <span>{</span><span>"job_id"</span>:17,<span>"class"</span><span>:</span><span>"Hampel<span title="\\">\\</span>JobRunner<span title="\\">\\</span>Job<span title="\\">\\</span>TestJob"</span>,<span>"status_message"</span><span>:</span><span>"Testing jobs"</span>,<span>"data"</span>:<span>{</span><span>"email"</span><span>:</span><span>"[email protected]"</span><span>}</span>,<span>"execution_time"</span><span>:</span><span>"0.95"</span><span>}</span><br><br><span>[</span><span>2019</span>-11-28 00:26:21<span>]</span> Hampel<span>\</span>JobRunner:TestJob: Job executed <span>in</span> <span>0.95</span> seconds <span>{</span><span>"completed"</span>:true,<span>"jobId"</span>:17,<span>"continueDate"</span>:null,<span>"continueDate_formatted"</span><span>:</span><span>""</span>,<span>"statusMessage"</span><span>:</span><span>""</span><span>}</span> <span>{</span><span>"job_id"</span>:17,<span>"unique_key"</span>:null,<span>"execute_class"</span><span>:</span><span>"Hampel<span title="\\">\\</span>JobRunner:TestJob"</span>,<span>"execute_data"</span>:<span>{</span><span>"email"</span><span>:</span><span>"[email protected]"</span><span>}</span>,<span>"manual_execute"</span>:0,<span>"trigger_date"</span>:1574900777,<span>"last_run_date"</span>:null,<span>"trigger_date_formatted"</span><span>:</span><span>"2019-11-28 00:26:17 UTC"</span>,<span>"last_run_date_formatted"</span><span>:</span><span>""</span><span>}</span><br><br>No <span>more</span> runnable <span>jobs</span> pending
No output will be shown when run in quiet mode - and more importantly, if this addon is disabled the logging code will not need to be removed. The important part is the if (!isset(\XF::app['cli.logger'])) return; line, which will abort if our Logger is not available.
Custom Cron task debugging
Using a similar mechanism, we can add debugging code to our custom Cron tasks too:
Add a slightly different function to your Cron tasks to call the log() function of our Logger class:
Code:
protected static function log($message, array $context = [])<br> {<br> // check to see if we actually have a logger available and abort if not<br> if (!isset(\XF::app['cli.logger'])) return;<br><br> /** @var Logger $logger */<br> $logger = \XF::app['cli.logger'];<br> $logger->log("XF\Job\Cron", $message, $context);<br> }
Then, simply call something like: self::log("some message about something happening", ['key' => 'value']); within your code to output information to the console when the Job Runner is executed in verbose mode.
Logger Trait
There is also a trait you can include in your classes: Hampel\JobRunner\Cli\LoggerTrait which implements some basic logging functions you may call from your code:
- getLogger
- log
- logQuiet (will show even if the -q option is specified for the Job Runner) - use this for critical errors only
- logNormal (will show for no verbosity or higher)
- logVerbose (will show only for the -v option or higher)
- logVeryVerbose (will show only for the -vv option or higher)
- debug (will show only if the -vvv option option is specified for the Job Runner)
Debugging Cron tasks
As of v2.0 beta 3, there are two new commands for working with XF cron tasks:
Show Crons
The hg:show-crons command will list all of your active XF cron tasks
Bash:
$ cmd.php hg:show-crons<br><br><span>19</span> active <span>cron</span> entries found<br><br>+---------------------------+----------------------+--------------------------+<br><span>|</span> ID <span>|</span> Next Run <span>(</span>UTC+10:00<span>)</span> <span>|</span> Addon <span>|</span><br>+---------------------------+----------------------+--------------------------+<br><span>|</span> forumStatistics <span>|</span> <span>29</span>-Sep-2020 06:53 <span>|</span> XF <span>|</span><br><span>|</span> emailBounce <span>|</span> <span>29</span>-Sep-2020 06:53 <span>|</span> XF <span>|</span><br><span>|</span> warningExpiry <span>|</span> <span>29</span>-Sep-2020 06:55 <span>|</span> XF <span>|</span><br><span>|</span> rebuildSearchForumCache <span>|</span> <span>29</span>-Sep-2020 07:00 <span>|</span> XF <span>|</span><br><span>|</span> memberStatsCache <span>|</span> <span>29</span>-Sep-2020 07:00 <span>|</span> XF <span>|</span><br><span>|</span> feeder <span>|</span> <span>29</span>-Sep-2020 07:02 <span>|</span> XF <span>|</span><br><span>|</span> cleanUpHourly <span>|</span> <span>29</span>-Sep-2020 07:10 <span>|</span> XF <span>|</span><br><span>|</span> emailUnsubscribe <span>|</span> <span>29</span>-Sep-2020 07:13 <span>|</span> XF <span>|</span><br><span>|</span> userGroupPromotions <span>|</span> <span>29</span>-Sep-2020 07:20 <span>|</span> XF <span>|</span><br><span>|</span> views <span>|</span> <span>29</span>-Sep-2020 07:30 <span>|</span> XF <span>|</span><br><span>|</span> trophy <span>|</span> <span>29</span>-Sep-2020 07:40 <span>|</span> XF <span>|</span><br><span>|</span> expireTempUserChanges <span>|</span> <span>29</span>-Sep-2020 07:42 <span>|</span> XF <span>|</span><br><span>|</span> deleteExpiredBans <span>|</span> <span>29</span>-Sep-2020 07:45 <span>|</span> XF <span>|</span><br><span>|</span> downgradeExpired <span>|</span> <span>29</span>-Sep-2020 07:50 <span>|</span> XF <span>|</span><br><span>|</span> fileCheck <span>|</span> <span>29</span>-Sep-2020 <span>10</span>:10 <span>|</span> XF <span>|</span><br><span>|</span> dailyStats <span>|</span> <span>29</span>-Sep-2020 <span>10</span>:30 <span>|</span> XF <span>|</span><br><span>|</span> cleanUpDaily <span>|</span> <span>29</span>-Sep-2020 <span>13</span>:00 <span>|</span> XF <span>|</span><br><span>|</span> activitySummaryEmail <span>|</span> <span>30</span>-Sep-2020 00:20 <span>|</span> XF <span>|</span><br><span>|</span> sitemap <span>|</span> <span>30</span>-Sep-2020 <span>15</span>:37 <span>|</span> XF <span>|</span><br>+---------------------------+----------------------+--------------------------+<br><br>The current <span>time</span> is: <span>29</span>-Sep-2020 06:52:05 <span>(</span>UTC+10:00<span>)</span>
There are three command line options you can specify:
- -a or --all shows all cron tasks, including disabled tasks
- -m or --method includes the class::method for each cron task
- -s or --sort specifies the sort column for the list (date, id or addon)
Run Cron
The hg:run-cron command will execute an XF cron task - simply specify a cron ID as the argument.
For example: cmd.php hg:run-cron activitySummaryEmail will run the "Send activity summary email" cron task.
By default, disabled cron tasks cannot be run - so you can override this by specifying the -f or --force option on the command line.
The same verbosity flags work here - so specify -v, -vv or -vvv to generate the desired level of output.