ActiveManage Docs ← Back to activemanage.co.uk

Tasks

The Task Engine

The Task Engine runs scheduled jobs — anything that should happen automatically on a cadence rather than in response to a user action. Maintenance jobs, recurring imports, billing runs, cleanup, scheduled reports, monitoring checks, automated reminders. If you'd write a cron job for it on a traditional Unix system, you'd write a Task in ActiveManage.

How it runs

A cron job (or equivalent scheduled trigger) on the server calls the platform's task runner every minute. The runner:

  1. Queries the .tasks table for tasks whose next-run time has been reached.
  2. For each due task, executes its handler (a PHP function or built-in action).
  3. Records the run in the Task Log with start/end timestamps and any output.
  4. Computes the next-run time based on the task's schedule.

The system-level cron entry that triggers all this is typically * * * * * /usr/local/bin/php /home/site/activemanage/taskengine.php. It runs every minute; tasks scheduled less frequently than once-a-minute are handled by the Task Engine deciding which to actually run.

Where tasks live

Architect Panel → Automation → Tasks. Each task has:

  • Name — internal name.
  • Schedule — cron-style expression.
  • Handler — the PHP function or built-in action to run.
  • Parameters — JSON object passed to the handler.
  • Enabled — toggle to disable temporarily.
  • Last run / Next run — automatic, computed by the engine.
  • Recent log entries — visible from the task detail page.

Three real-world tasks

Example 1: Nightly cleanup

Name: "Purge soft-deleted records". Schedule: 0 2 * * * (2am daily). Handler: a custom PHP function that hard-deletes rows where MSTisdeleted = 1 and they've been soft-deleted for more than 90 days. Keeps the database from growing unboundedly with soft-deleted records.

Example 2: Monthly billing run

Name: "Monthly subscription billing". Schedule: 0 3 1 * * (3am on the 1st of each month). Handler: iterates subscription packages, charges each active subscription via Stripe, records the transaction, sends invoice emails. Critical infrastructure for any SaaS install.

Example 3: Hourly status check

Name: "Health check external dependencies". Schedule: 0 * * * * (every hour on the hour). Handler: calls each configured external API, records response time and status, alerts if any are failing. Provides visibility into upstream health.

Screenshot of the Tasks admin showing a list of scheduled tasks with their names, schedules, last-run timestamps, and enabled toggles

The Task Log

Every task execution is recorded. See the Task Log article in this section for details on what's captured and how to debug failed tasks.

Creating a Scheduled Task

From the Architect Panel → Tasks, click New. The configuration form asks you to define when the task should run and what it should do when it does.

Configuration

  • Name — descriptive internal name.
  • Schedule — cron-style expression. See the Cron-style Scheduling article for the syntax.
  • Handler — pick a built-in action or specify a PHP function name. Built-in actions cover common patterns (purge records, send digest emails, sync external data). Custom PHP handlers handle anything else.
  • Parameters — JSON object passed to the handler. The handler uses these to know what specifically to do (e.g. "which datastore to clean up", "which template to send", "what URL to ping").
  • Enabled — toggle to disable temporarily without deleting the task.
  • Timeout — maximum runtime in seconds before the task is killed (for tasks that might hang).
  • Retry on failure — whether failed runs should retry, and how many times.

Schedule examples

Cron syntax is five fields: minute, hour, day-of-month, month, day-of-week. Common patterns:

  • * * * * * — every minute.
  • */5 * * * * — every 5 minutes.
  • 0 * * * * — top of every hour.
  • 0 2 * * * — 2am every day.
  • 0 9 * * 1-5 — 9am Monday to Friday.
  • 0 0 1 * * — midnight on the 1st of each month.
  • 0 0 1 1 * — midnight on January 1st (annual).

One-off vs recurring

Most tasks are recurring — they fire on a schedule indefinitely until you disable or delete them. For one-off tasks ("run this once next Tuesday at 9am"):

  1. Set the schedule to match the desired time (e.g. 0 9 * * 2 for 9am Tuesday).
  2. Add logic to the handler that disables the task after successful execution (or use the platform's one-shot task feature if available).

Idempotency

Tasks should be idempotent — running the same task twice should produce the same end state as running it once. This matters because:

  • Tasks can occasionally fire twice (e.g. if the cron entry overlaps a long-running task).
  • Retries on failure mean a task that partially completed might be retried.
  • Manual re-runs (via the Re-run action in the Task Log) should be safe.

Idempotency is typically achieved by:

  • Checking before acting (don't insert a record if it already exists; don't send an email if it's already been sent).
  • Using transactions to make changes all-or-nothing.
  • Recording task progress so a re-run can pick up where it left off.

Three real-world task configurations

Example 1: Daily report email

Schedule: 0 8 * * 1-5 (8am weekdays). Handler: sendDailyReport. Parameters: {"template": "daily-summary", "recipients": ["team@acme.com"]}. Generates yesterday's metrics and emails the team.

Example 2: Sync customers from CRM

Schedule: */15 * * * * (every 15 minutes). Handler: syncCustomersFromCRM. Parameters: {"limit": 100, "since": "last_run"}. Pulls updates from the CRM since the last successful run; idempotent so duplicates are detected and skipped.

Example 3: One-off historical data backfill

Schedule: 0 22 31 12 * (set to a far-future date). Handler: backfillHistoricalOrders. Parameters: {"start_year": 2020, "end_year": 2024}. Self-disables after successful completion. Used once during a data migration and then disabled forever.

Screenshot of the New Task form showing Name, Schedule, Handler, Parameters (as JSON), Enabled toggle, Timeout, and Retry fields

Viewing the Task Log

Every task execution is recorded in the Task Log. Useful for verifying schedules are firing on time, debugging failures, monitoring task duration, and tracking output that tasks produce.

What's recorded

Per log entry:

  • Task name — which task ran.
  • Start timestamp.
  • End timestamp (or null if still running).
  • Duration — computed end - start.
  • Result — Success, Failed, Timed Out, Skipped.
  • Output — any text the handler echoed or returned.
  • Error message — if Failed, the error reason.
  • Stack trace — if Failed and stack-trace capture is on, the full PHP stack.
  • Resources consumed — memory usage, query count (when available).

Where to find it

Architect Panel → Automation → Task Log. The list is filterable by task name, status, and date range. Each entry can be clicked into for the full output and stack trace.

Common queries

1. "Did the nightly task run last night?"

Filter by task name + last 24 hours. You'll see the run (if it happened) with its result. If it's missing entirely, the schedule didn't fire — check the cron entry on the server.

2. "Why did this task error?"

Click into the failed entry. Read the error message and stack trace. Common causes:

  • External API down or rate-limited.
  • Database lock timeout (long-running task blocked by another query).
  • Memory exhausted (task processed too much in one pass).
  • PHP exception in the handler code.
  • Configuration changed since the task was written.

3. "How long does this task usually take?"

Filter by task name and sort by duration. Spot tasks that are getting slower over time (typically a sign that they're scaling badly with growing data volume).

4. "Which tasks failed in the last week?"

Filter by status = Failed and date range. Useful for end-of-week health reviews — any task that's failing repeatedly is a problem to investigate.

Retention

By default, log entries are kept indefinitely. For very active task installs (hundreds of tasks running every minute), this grows the database significantly over time. Set up a meta-task that purges entries older than your retention policy (typically 30-90 days).

Re-running

From the Task Log entry's detail page, there's a Re-run action. Useful for:

  • Manually re-triggering a failed task after fixing the underlying problem.
  • Running an ad-hoc execution to test changes.
  • Catching up after a planned outage where tasks didn't fire on schedule.

Screenshot of the Task Log admin showing a list of task runs with columns for task name, start/end timestamps, duration, status, and a Re-run button per row

Tip: Configure email alerts on failed tasks. A simple meta-task that runs every 15 minutes and emails an admin when any task in the last interval has failed catches issues quickly. Without an alert, failures can go undetected for days because admins rarely browse the Task Log proactively.