Schedules
createWorkflowSchedule wires a workflow's wire-encoded payload into a Temporal schedule's start-workflow action — cron for durable workflows, managed by the Temporal cluster.
const wf = yield* WorkflowClient;
yield* wf.createSchedule({
scheduleId: "nightly-reconcile",
workflow: ReconcileFlow,
payload: { scope: "all" },
spec: { calendars: [{ hour: 3, minute: 0 }] },
});The standalone form returns the Temporal ScheduleHandle for administration (trigger, pause, delete):
import { createWorkflowSchedule } from "@springbird/effect-temporal/engine-client";
const handle = yield* createWorkflowSchedule({
client,
scheduleId: "nightly-reconcile",
workflow: ReconcileFlow,
payload: { scope: "all" },
taskQueue: "orders",
spec: { intervals: [{ every: "1 hour" }] },
});spec is Temporal's own ScheduleSpec — intervals, calendars, jitter, time zones all apply.
Creating a schedule whose id already exists fails typed with ScheduleAlreadyExistsError — the routine re-registration condition, surfaced as a tag so deploy-time idempotent setup can catch it:
yield* wf.createSchedule({ scheduleId, workflow, payload, spec }).pipe(
Effect.catchTag("ScheduleAlreadyExistsError", () => Effect.void), // already registered
);Fired runs sit outside the idempotency contract
Each fire starts the workflow with a schedule-generated workflow id (the schedule id plus a timestamp), not the digest execution id. That has two consequences:
Address fired runs by their generated ids — read them off the schedule's recent actions, then use the ordinary typed paths:
tsconst description = await handle.describe(); const firedId = description.info.recentActions[0]?.action.workflow.workflowId; const result = yield* ReconcileFlow.poll(firedId);A digest-addressed
executecan run concurrently with a fired run. If the workflow must be a singleton, make the schedule the only starter, or funnel manual triggers throughhandle.trigger()instead ofexecute.
Overlap between fires is governed by the schedule's own overlap policy (spec/policies on the Temporal schedule), which passes through untouched.
Payloads are fixed per schedule
The payload is encoded once, at schedule creation. A "run this nightly for each tenant" shape is one schedule per tenant, or one schedule whose workflow fans out to children.