Enterprise Patterns

Scheduling

External orchestration of when work happens

Schedules in PURISTA are trigger contracts, not a runtime scheduler. You declare when something should happen. Production scheduling, state management, and missed-run recovery stay with external schedulers (Cron, Airflow, cloud schedulers, or Temporal).

Declaring a schedule

Use the schedule builder to define when and what to trigger:

const monthlyBillingSchedule = userServiceV1ServiceBuilder
  .getScheduleBuilder('monthlyBillingCycle', 'Trigger monthly billing on the 1st')
  .emitEvent('billing.monthlyCycleDue', {
    expression: { kind: 'cron', value: '0 2 1 * *' },
    timezone: 'Europe/Berlin',
    concurrencyPolicy: 'forbid',
    missedRunPolicy: 'runOnce',
    idempotencyKey: 'payload.cycleId',
    payloadSchema: z.object({ cycleId: z.string() }),
  })

userServiceV1ServiceBuilder.addScheduleDefinition(monthlyBillingSchedule)

Schedule targets

TargetUse whenExample
EventMultiple consumers may reactbilling.monthlyCycleDue
QueueExactly one durable background taskMonthly report generation
CommandShort, idempotent logicCleanup routine

Prefer events for business facts — they allow multiple subscribers without coupling.

Schedule options

OptionDescriptionExample
expressionWhen to trigger (cron or interval){ kind: 'cron', value: '0 2 1 * *' }
timezoneTimezone for cron evaluationEurope/Berlin
concurrencyPolicyWhat to do if previous run hasn’t finishedforbid, allow, replace
missedRunPolicyHow to handle missed triggersrunOnce, skip, backfill
idempotencyKeyField used for deduplicationpayload.cycleId

Architecture

flowchart LR
    SCH["External Scheduler<br/>(Cron / Airflow / Cloud)"] -->|reads manifest| EXP["PURISTA Export"]
    SCH -->|triggers| EB["Event Bridge"]
    EB -->|event| SUB["Subscription"]
    EB -->|enqueue| Q["Queue"]
    EB -->|command| CMD["Command"]

The scheduler reads the PURISTA schedule manifest (registered automatically at service start) and configures itself. At trigger time, it sends the appropriate message to the event bridge.

Registering schedules

Schedule registration happens automatically when the service starts. No runtime CLI command is needed. When the service instance starts, it registers all declared schedules with the event bridge, which in turn configures the appropriate external scheduler.

Configure your external scheduler to send the appropriate message to the event bridge at trigger time:

  • AWS EventBridge — scheduled rules with Lambda targets
  • Google Cloud Scheduler — cron jobs with Pub/Sub targets
  • Temporal — scheduled workflows
  • Airflow — DAGs with HTTP or message triggers

Local development

For local testing, use the DefaultEventBridge with a local runner:

import { DefaultEventBridge } from '@purista/core'

const eventBridge = new DefaultEventBridge()
await eventBridge.start()

const userService = await userServiceV1Service.getInstance(eventBridge)
await userService.start()

Design guidelines

  • Keep schedules declarative — they describe intent, not implementation
  • Use events for business factsbilling.cycleDue not runBillingJob
  • Make payloads idempotent — the same trigger may fire more than once
  • Handle missed runs explicitly — choose runOnce or backfill based on business rules

When to use scheduling

  • Periodic background jobs (billing, reporting, cleanup)
  • Time-based business rules (promotions, maintenance windows)
  • Delayed actions (send reminder after 24 hours)
  • Recurring data imports or exports

Common pitfalls

  • Implementing a scheduler inside PURISTA. Use external schedulers for production.
  • Non-idempotent payloads. The same trigger may fire twice. Design for it.
  • Ignoring timezone. Cron expressions without timezone are ambiguous.
  • Missing concurrency policy. Without forbid, overlapping runs corrupt state.

Checklist

  • Schedule is declarative (intent, not implementation)
  • Payload is idempotent
  • Timezone is explicit
  • Concurrency policy matches business needs
  • Missed run policy is defined
  • Schedules are registered and verified at service startup
  • External scheduler is configured and monitored

Related

Read Next
Observability

from Observability & Operations