Skip to content

Async & Scheduled Tasks

StackRivet separates two things that look similar but have different boundaries:

  • Async tasks — “submit and run” heavy work: imports, exports, code-generation writes, asset processing. The concern is a state machine, idempotency, cancel, retry, timeout and error categories.
  • Scheduled tasks — cron / fixed-rate work: visual task management, cluster de-duplication, manual trigger, retry, alerts and audit.

Heavy work never blocks a request thread. It is submitted as a task and tracked through a state machine:

stateDiagram-v2
  [*] --> pending
  pending --> running
  pending --> cancelled
  running --> success
  running --> failed
  failed --> retrying
  retrying --> running
  running --> cancelled
  success --> [*]
  cancelled --> [*]

Each task carries an idempotencyKey so a retry doesn’t run the work twice, plus retry, cancel, timeout and an error category. The stackrivet-task module owns this machine, and the admin UI ships a /tasks page to filter, submit, run, cancel, retry and inspect tasks.

This is why imports, exports and generator writes are listed as async work in the Architecture — a 50 MB import or a large export must not hold a web thread.

Scheduling is decoupled from any specific scheduler framework. The stackrivet-task module defines a small Scheduler SPI — ScheduledJobHandler, ScheduledJobContext, ScheduledJobResult, ScheduledJobRegistry, SchedulerAdapter, SchedulerCapability — and a business job depends only on these StackRivet interfaces, never on a third-party scheduler’s API.

The default release embeds only StackRivet’s own scheduling abstraction plus a local scheduler bridge that dispatches jobs by handler name (and restores the tenant context at the execution boundary). There is no GPL component in the default runtime — an earlier XXL-Job experiment was reverted precisely because XXL-Job is GPL-3.0 and StackRivet is Apache-2.0 with a commercial Enterprise tier.

For distributed scheduling, SnailJob (Apache-2.0) is the priority adapter, shipped as an optional module (stackrivet-scheduler-snailjob). It is:

  • Activated only when stackrivet.scheduler.snailjob.enabled=true — even if the jar is on the classpath it stays dormant by default.
  • Kept out of the base runtime: stackrivet-app does not depend on it, so the default dependency tree has zero scheduler-framework code.
  • A bridge that maps SnailJob’s callbacks onto the same SchedulerAdapter SPI, adding distributed retry, replay governance, alerts and a console.

PowerJob (complex DAG / MapReduce) and ElasticJob (existing ZooKeeper users) are available as further optional adapters; XXL-Job is documented for migration/external triggering only and is never a StackRivet dependency.

The Scheduler SPI, local task examples and the /tasks admin page are in Community. The SnailJob adapter and distributed retry / replay governance are Pro / Enterprise — see the pricing page. Because the SPI is in Community, your job code is written against StackRivet interfaces from day one and gains distributed scheduling later without changes.