Overview
The actor system’s scheduler can target grains as well as actors.ScheduleGrainOnce, ScheduleGrain and
ScheduleGrainWithCron take a *GrainIdentity where the actor methods take a *PID, and deliver the message to the
grain once after a delay, repeatedly at a fixed interval, or on a cron expression. Everything else is shared with the
actor scheduler: the underlying go-quartz scheduler, the reference-based management API
(CancelSchedule, PauseSchedule, ResumeSchedule, ListSchedules), the ScheduleOption values, the scheduler
metrics, and the cluster rules for cron.
A grain schedule is held by the scheduler of the node that registered it, not by the grain. It outlives the grain’s
activation: a grain that passivated between two deliveries is activated again by the next one. It is not persisted, so
it does not survive a restart of the node, exactly like an actor schedule.
Grain schedules are not grain timers. A timer is registered by the grain for itself and is cancelled
when the grain deactivates. A schedule can be registered by any code holding the grain identity and keeps firing until
it is cancelled. Read Grain schedules vs grain timers before using a schedule for a
grain’s own periodic work.
API
- ScheduleGrainOnce: Deliver once after the delay.
- ScheduleGrain: Deliver at a fixed interval (repeating).
- ScheduleGrainWithCron: Deliver according to a cron expression in the Quartz format.
- CancelSchedule, PauseSchedule, ResumeSchedule, ListSchedules: Shared with actor schedules and keyed by the schedule reference.
Options
The methods take the sameScheduleOption values as the actor methods:
- WithReference: Set a unique ID for cancel, pause or resume. Strongly recommended if you plan to manage the
schedule later, and required for
ScheduleGrainWithCronin cluster mode. Without it an auto-generated UUID is used. A reference names one schedule on the node: registering another schedule, actor or grain, under a reference that is still in use fails with go-quartz’squartz.ErrJobAlreadyExists. - WithSender: Has no effect on a grain schedule. A grain has no sender notion, so
GrainContextexposes none.
Example
Scheduling to a grain
Delivery
Every tick delivers the message with a one-wayTellGrain (see
Tell: acknowledged or one-way). Grain schedules therefore have the
following properties:
- Location transparency: The grain is located, or activated, wherever it lives when the tick fires: on the local node, or on the node that owns it in cluster mode. The registering node and the owning node need not be the same.
- Reactivation: A grain that passivated since the previous tick is activated again by the delivery, the way any
TellGrainto a passivated grain activates it: the grain is built as a zero value of its struct type andOnActivateruns again. The grain kind must be registered on the node that activates it, throughGrainOfon that node,RegisterGrainKind, orClusterConfig.WithGrains. - Passivation activity: The delivered message rides the grain mailbox like any other message, so it refreshes the grain’s passivation activity and counts toward message-count-based passivation strategies. An interval shorter than the grain’s deactivation timeout keeps the grain alive for as long as the schedule runs.
- Handler failures: A failure the handler reports through
ErrorUnhandled, or a panic inOnReceive, is recorded as a deadletter naming the grain as receiver. Nothing is retried. - Delivery failures: An error before the message is enqueued, for example a grain kind that is not registered on the firing node, an activation failure, or a transport failure toward the owning node, is neither returned to anyone nor logged by the scheduler: that tick is lost. Interval and cron schedules keep firing on the next tick; a one-shot is gone.
- Ordering: Deliveries are processed one at a time, serialized with the grain’s other messages. The scheduler fires at a fixed cadence, so ticks of a handler slower than the interval queue up in the mailbox.
- Cancellation:
CancelSchedulestops future ticks. A tick that already handed its message to the grain is not recalled.
Cluster mode
The rules are those of the actor scheduler:ScheduleGrainWithCrondelivers exactly once per tick across the cluster. Every node that registers the schedule runs its own cron trigger; before delivery each node races to claim the tick, and only the winner callsTellGrain, which routes the message to the node that owns the grain.WithReferenceis required, since the claim is keyed on the reference, and the cron expression is evaluated in UTC. The call is rejected withErrScheduleReferenceRequiredwithout a reference.ScheduleGrainandScheduleGrainOncestay node-local. The same schedule registered on several nodes delivers once per node per tick, all to the single activation of the grain.CancelScheduleonly stops the trigger on the node where it is called, for cron as for interval schedules.
Errors
- ErrSchedulerNotStarted: The actor system, and with it the scheduler, is not started.
- ErrInvalidGrainIdentity: The identity fails validation, for example an empty name.
- ErrScheduleReferenceRequired:
ScheduleGrainWithCronin cluster mode withoutWithReference. - ErrScheduledReferenceNotFound: Cancel, pause or resume with an unknown reference, or a one-shot that already fired.
- An invalid cron expression is rejected with the parser’s error; a reference still in use with
quartz.ErrJobAlreadyExists.
Introspection
ListSchedules reports grain schedules alongside actor schedules. A ScheduleInfo carries the reference and its
target: Path for an actor schedule, Grain for a grain schedule. Exactly one of the two is set.
Introspection
scheduler.scheduled.count and scheduler.cancelled.count.
Grain schedules vs grain timers
Both can deliver a message to a grain later, and a grain can register either for itself. They differ in who owns the entry:- Who schedules: Grain timers: The grain itself, from
GrainContextorGrainProps. Grain schedules: Any code holding anActorSystemand the grain identity, including the grain throughctx.ActorSystem(). - Target: Grain timers: Always the scheduling grain. Grain schedules: Any grain.
- Held by: Grain timers: The activation. Grain schedules: The scheduler of the registering node.
- Passivation: Grain timers: All cancelled on deactivation; never reactivate the grain. Grain schedules: Survive passivation; each delivery reactivates the grain.
- Passivation clock: Grain timers: A tick does not refresh it unless
WithTimerKeepAlive. Grain schedules: Every delivery refreshes it. - Node restart: Both are lost.
- References: Grain timers: Scoped to the grain; a duplicate replaces the timer. Grain schedules: Scoped to the node; a duplicate is rejected.
- Management: Grain timers:
CancelScheduleon the grain context. Grain schedules:CancelSchedule,PauseSchedule,ResumeScheduleandListScheduleson the actor system. - Cluster cron: Grain timers: No arbitration needed. Grain schedules: Claim per tick,
WithReferencerequired, UTC. - Handler failure: Grain timers: Logged as a warning. Grain schedules: Recorded as a deadletter.
See also
- Actor scheduling: The shared scheduler, the cron format, and cluster-wide single fire
- Grain Timers: Volatile, activation-scoped timers for a grain’s own periodic behavior
- Grains overview: Identity, messaging and the one-way tell