Scheduled Tasks - edmozley/freeitsm GitHub Wiki

Scheduled tasks (cron jobs)

Some things in FreeITSM cannot happen while somebody is looking at a screen. An SLA breaches at 3am. A contract expires in 30 days. A developer comments on a Jira issue and nobody is watching. For those, FreeITSM needs a small job that wakes up on a timer.

None of them are set up for you. A fresh install has no scheduled tasks at all, and the features that depend on them fail silently โ€” nothing errors, nothing appears in a log, the feature simply never happens. This page lists every one, what breaks without it, and how to set it up on Windows and Linux.

โš ๏ธ Silent is the important word. A tracker whose status never changes looks exactly like a tracker where nothing has happened. An SLA that never breaches looks like good service. If a time-based feature "doesn't seem to work", check this page first.


The nine jobs

Job What it does What breaks without it Suggested interval
cron/integration_poll.php Asks Jira (and other issue trackers) what has changed Issue status never updates and comments never come back โ€” see Issue trackers every 5 minutes
cron/sla_breach_check.php Checks open tickets against their SLA targets SLA warning and breach notifications are never sent every 5 minutes
cron/webhook_deliveries.php Delivers queued outbound webhooks, with retries Webhooks fired by workflows sit in the queue and never send every 1 minute
cron/workflow_scheduled.php Fires time-based workflow triggers Rules like "this contract expires in 30 days" never run every 5 minutes
cron/task_recurrence.php Creates the next occurrence of tasks that repeat on a fixed schedule, once work on it can start Fixed-schedule repeats never appear. Repeats set to after completion are unaffected โ€” see the note below once a day
cron/calendar_sync_pull.php Reads changes back out of analysts' calendars - Microsoft 365 and CalDAV servers alike Moving or deleting a synced appointment in a calendar never reaches FreeITSM. The outbound half still works โ€” see Ticket calendar sync every 5 minutes
cron/attachment_extract.php Reads the text out of PDFs and scanned documents so they can be searched Nothing immediately โ€” see the note below every 5 minutes
scripts/documents_maintenance.php Reads the text out of files attached through Documents, and collects documents whose record has been deleted Nothing immediately โ€” see the note below every 5 minutes
scripts/directory_sync.php --all Imports people from every enabled directory (LDAP / Active Directory) and address book (CardDAV) โ€” see Directory sync and Contact details Nothing immediately, and nothing loudly. People are imported only when somebody presses Run on the source's own page, so a new starter added to your directory on Monday does not exist in FreeITSM until a human remembers once or twice a day

Two of these are not in cron/. scripts/documents_maintenance.php and scripts/directory_sync.php live with the other command-line scripts, so listing the cron/ folder will not show them. They are scheduled jobs in every other respect.

The people import was missing from this page until 1.8.0, which is worth saying plainly: it has been schedulable since directory sync shipped, and anyone running a directory had no way to find that out from the documentation. If you use LDAP or Active Directory today and have been pressing Run by hand, this is the job you wanted.

--all means every enabled source of either kind. It skips anything switched off, and skips OIDC providers entirely โ€” they sign people in and import nobody. Add --preview to have it report what it would do and write nothing, which is the sensible way to see what a schedule is about to start doing on its own. A single source can be run on its own with --provider=<id>.

The first four each have a detailed setup document in the docs/ folder of the application: integration-poll-cron-setup.md, sla-cron-setup.md, webhook-cron-setup.md and workflow-scheduled-cron-setup.md.

An occurrence appears when work on it can START, not when it falls due. A repeat keeps the gap between starting and being due, so a task that needs a fortnight appears a fortnight before its due date and a task with no start date appears on the day. This is why the job runs daily rather than hourly, and why the board only ever holds work you could actually be doing: the lead time is the task's own duration, which you have already given it, rather than a number to configure.

Only half of recurring tasks needs this job. A task set to repeat after completion makes its next occurrence inside the request that completed the last one, so it works on an installation with no scheduled tasks at all. Only fixed schedule repeats โ€” the ones that arrive on their dates whether or not the previous one was finished โ€” need this job running. The calendar draws future fixed-schedule occurrences faintly before they exist, so you can see the plan either way, but the actual tasks are created by this job. See Tasks.

The attachment job is the odd one out, deliberately. It is the only one whose absence is not silent failure. Without it, waiting documents are still read โ€” a few at a time, whenever somebody is using FreeITSM โ€” so attachment searching works on an installation with no scheduled tasks at all. The job just keeps up with a busy service desk rather than trickling. Both behaviours can be turned off in Tickets โ†’ Settings โ†’ Indexing, and neither does anything until a document reader is set up under System โ†’ Integrations โ†’ Apache Tika. See Attachment text extraction.

The documents job is the other one whose absence is not silent failure. Attaching a file reads it there and then, with a few seconds to do it in โ€” right for one file, useless for somebody who has just attached fifty warranty PDFs, which then sit unread until the next upload nudges the queue. The job clears that backlog. Its second half matters more quietly: a document attached to a contract survives the contract being deleted, because the link can point at any kind of record and so no database rule can clean it up. The document becomes invisible immediately โ€” every permission check asks whether its parent still exists โ€” but the file stays on the disk forever. Nothing leaks and nothing is lost without this job; you get prompt searching and disk that does not slowly fill with files nobody can reach. See Attached documents.

Which do I actually need?

Only the ones matching the features you use. If you have no issue tracker connected, the tracker poll does nothing useful. If you have never written a workflow, the scheduled-workflow job has nothing to fire. If in doubt, set them all up โ€” an unused job costs a second of CPU and prints one line saying it had nothing to do.


Windows (Task Scheduler)

Run these in a Command Prompt opened as Administrator. Adjust the two paths if your PHP or FreeITSM lives elsewhere.

schtasks /create /tn "FreeITSM Tracker Poll" /tr "C:\wamp64\bin\php\php8.4.0\php.exe C:\wamp64\www\freeitsm-app\cron\integration_poll.php" /sc minute /mo 5 /ru SYSTEM

schtasks /create /tn "FreeITSM SLA Breach Check" /tr "C:\wamp64\bin\php\php8.4.0\php.exe C:\wamp64\www\freeitsm-app\cron\sla_breach_check.php" /sc minute /mo 5 /ru SYSTEM

schtasks /create /tn "FreeITSM Webhooks" /tr "C:\wamp64\bin\php\php8.4.0\php.exe C:\wamp64\www\freeitsm-app\cron\webhook_deliveries.php" /sc minute /mo 1 /ru SYSTEM

schtasks /create /tn "FreeITSM Scheduled Workflows" /tr "C:\wamp64\bin\php\php8.4.0\php.exe C:\wamp64\www\freeitsm-app\cron\workflow_scheduled.php" /sc minute /mo 5 /ru SYSTEM

schtasks /create /tn "FreeITSM Recurring Tasks" /tr "C:\wamp64\bin\php\php8.4.0\php.exe C:\wamp64\www\freeitsm-app\cron\task_recurrence.php" /sc daily /st 01:00 /ru SYSTEM

schtasks /create /tn "FreeITSM Calendar Sync Pull" /tr "C:\wamp64\bin\php\php8.4.0\php.exe C:\wamp64\www\freeitsm-app\cron\calendar_sync_pull.php" /sc minute /mo 5 /ru SYSTEM

schtasks /create /tn "FreeITSM Documents Maintenance" /tr "C:\wamp64\bin\php\php8.4.0\php.exe C:\wamp64\www\freeitsm-app\scripts\documents_maintenance.php --quiet" /sc minute /mo 5 /ru SYSTEM

schtasks /create /tn "FreeITSM Attachment Text" /tr "C:\wamp64\bin\php\php8.4.0\php.exe C:\wamp64\www\freeitsm-app\cron\attachment_extract.php" /sc minute /mo 5 /ru SYSTEM

schtasks /create /tn "FreeITSM People Import" /tr "C:\wamp64\bin\php\php8.4.0\php.exe C:\wamp64\www\freeitsm-app\scripts\directory_sync.php --all --quiet" /sc daily /st 02:00 /ru SYSTEM

Things that catch people out on Windows

  • If either path contains a space, the command above will fail. Put the whole thing in a .bat file and point the task at that instead โ€” far easier than fighting schtasks quoting.
  • /ru SYSTEM tasks are invisible to a normal user. Task Scheduler run without elevation will not list them, and neither will PowerShell's Get-ScheduledTask. Open Task Scheduler as administrator to see them. A task you cannot see is not necessarily a task that does not exist.
  • Last Run Result of 0x41303 means "has not run yet" โ€” normal for a task you have just created. It should become 0x0 after its first run.
  • Check the task is Enabled, not merely present. A disabled task sits in the list looking perfectly healthy.

Linux (cron)

*/5 * * * * /usr/bin/php /var/www/freeitsm-app/cron/integration_poll.php    >/dev/null 2>&1
*/5 * * * * /usr/bin/php /var/www/freeitsm-app/cron/sla_breach_check.php    >/dev/null 2>&1
*   * * * * /usr/bin/php /var/www/freeitsm-app/cron/webhook_deliveries.php  >/dev/null 2>&1
*/5 * * * * /usr/bin/php /var/www/freeitsm-app/cron/workflow_scheduled.php  >/dev/null 2>&1
0   1 * * * /usr/bin/php /var/www/freeitsm-app/cron/task_recurrence.php     >/dev/null 2>&1
*/5 * * * * /usr/bin/php /var/www/freeitsm-app/cron/calendar_sync_pull.php  >/dev/null 2>&1
*/5 * * * * /usr/bin/php /var/www/freeitsm-app/cron/attachment_extract.php  >/dev/null 2>&1
*/5 * * * * /usr/bin/php /var/www/freeitsm-app/scripts/documents_maintenance.php --quiet >/dev/null 2>&1
0   2 * * * /usr/bin/php /var/www/freeitsm-app/scripts/directory_sync.php --all --quiet >/dev/null 2>&1

Drop the >/dev/null while you are testing, so cron emails you the output.

Running one by hand

Useful for testing, or before you have set the schedule up. From the application folder:

php cron/integration_poll.php

Each job prints what it did. The tracker poll, for example:

Jira                         checked   1, changed  0
    comments: 1 seen, 1 imported

Checking they are working

The most reliable test is not "does the task exist" but "did something happen that only the job could have caused".

  • Tracker poll โ€” change an issue's status in Jira, wait for two intervals, and see whether the pill on the linked ticket follows.
  • Webhooks โ€” fire a workflow that sends one, then check the delivery queue empties.
  • SLA โ€” the notification arrives, or it does not.
  • Documents โ€” attach a file to anything, then search for a word that is only inside it. Before the job has run the file is found by its name only; afterwards, by its contents.
  • Recurring tasks โ€” set a task to repeat on a fixed schedule with a date that has already passed, run the job by hand, and the next occurrence should appear. Running it twice must not produce two: creating an occurrence is idempotent on the series and the date. To check the start-date rule, give the task a start date a week before its due date and a repeat due a week from now โ€” it should be created straight away, dated in the future.

๐Ÿ’ก Each job refuses to run more often than a minimum interval, and each connection has its own interval too. So running a job twice in quick succession may print "No connections due" or "Rate limited". That is the job protecting itself, not a fault โ€” wait and run it again.


What is not a scheduled task

Worth knowing, so you do not go looking for a job that does not exist โ€” or create one that should not.

  • Incoming email. Mailboxes are checked by the browser while an analyst has the ticket list open, not by a scheduled job. Mail therefore arrives when somebody is working, which is usually what you want, but it does mean nothing is collected overnight with every browser closed.
  • Snoozed tickets waking up. There is no job. A snoozed ticket reappears because the snooze time has passed โ€” it is read from the clock whenever the folder is drawn.
  • InTune synchronisation. scripts/intune_worker.php and intune_app_worker.php look like cron jobs but are not. The application starts them itself when you run a sync. Do not schedule them.

See also: Installation ยท Issue trackers (Jira) ยท Workflows ยท Webhooks