Normalizes scheduler metadata for cron-triggered workflow starts.
Cron activation is intentionally host-owned: a host app decides when a
declared cron trigger fires and queues a Squidie.Executor.Payload.cron/3
payload. This module translates that delivery payload plus the compiled
workflow trigger definition into the durable context stored on the new run.
The persisted shape is reserved under run.context.schedule and is meant to
answer two different questions:
- what logical schedule window was intended by the scheduler
- when Squidie actually received and started processing the signal
- which stable idempotency key, when configured, protects the logical start
Keeping both timestamps matters because delayed delivery is normal in durable runtime systems. Workflow steps should not infer their schedule window from current wall-clock time; they should read the intended window from the run context.
The metadata is stored in run context rather than workflow payload so it does not participate in the workflow's business input contract. It also means the metadata survives reload, inspection, explanation, and replay without adding a database column for one trigger kind.
Summary
Functions
Builds the durable run context for one cron activation.
Types
@type t() :: %{ :workflow => String.t(), :trigger_name => String.t(), :cron_expression => String.t(), :timezone => String.t(), :received_at => String.t(), optional(:signal_id) => String.t(), optional(:idempotency) => :return_existing_run | :skip_duplicate, optional(:idempotency_key) => String.t(), optional(:intended_window) => map() }
Functions
@spec cron_context(module(), Squidie.Workflow.Definition.trigger(), map()) :: {:ok, %{schedule: t()}} | {:error, {:invalid_schedule_signal_id, term()}} | {:error, {:invalid_schedule_intended_window, term()}} | {:error, {:missing_schedule_idempotency_key, atom()}}
Builds the durable run context for one cron activation.
The workflow and trigger definition contribute stable declarative data such
as the workflow name, trigger name, cron expression, and timezone. The
payload contributes scheduler-delivery data such as signal_id and
intended_window. If the scheduler omits signal_id, Squidie derives one
from the workflow, trigger, and intended window when both window bounds are
present. The runtime adds
received_at at activation delivery time, so operators can compare scheduler
intent against actual processing. Any received_at value in the payload is
ignored because this timestamp belongs to the runner boundary.
When the cron trigger opts into idempotency, the runtime also stores
idempotency and idempotency_key under the schedule context. The key is the
scheduler signal_id, either supplied by the host scheduler or derived from a
complete intended window. Without that identity, Squidie rejects the start
because it cannot prove whether the activation is new or a duplicate.