Documentation
¶
Overview ¶
Package lifecycle provides a shared, testable scheduler for async state transitions. EC2 instances, ECS tasks, and RDS instances all need delayed state changes (e.g. pending → running, creating → available). This package provides a single abstraction instead of each service hand-rolling time.AfterFunc/goroutine/cancel patterns.
Index ¶
- func ScopedKey(region, id, transition string) string
- type Scheduler
- func (s *Scheduler) After(key string, delay time.Duration, fn func())
- func (s *Scheduler) AfterScoped(region, id, transition string, delay time.Duration, ...)
- func (s *Scheduler) Cancel(key string) bool
- func (s *Scheduler) CancelScoped(region, id, transition string) bool
- func (s *Scheduler) PendingCount() int
- func (s *Scheduler) Stop(ctx context.Context)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Scheduler ¶
type Scheduler struct {
// contains filtered or unexported fields
}
Scheduler manages keyed delayed callbacks. Each service creates its own Scheduler instance (no global state, DI-friendly).
func NewScheduler ¶
NewScheduler creates a Scheduler using the given clock. Production: clock.New(). Tests: clock.NewMock() for instant time skips.
func (*Scheduler) After ¶
After schedules fn to run after delay. Key identifies the transition (e.g. "i-abc123:terminate"). If a transition with the same key is already pending, it is cancelled before the new one is scheduled.
When delay is 0 and the clock is a real clock (not a mock), fn is executed synchronously within this call. This ensures that subsequent API calls immediately see the updated state instead of racing with a goroutine. With a mock clock, 0-delay timers remain pending until clock.Add is called, preserving test-time control.
func (*Scheduler) AfterScoped ¶
func (s *Scheduler) AfterScoped(region, id, transition string, delay time.Duration, fn func(ctx context.Context))
AfterScoped schedules fn to run after delay for a resource that lives in a region-keyed store. It exists because the plain After callbacks run outside any request context: a bare context.Background() resolves to the DEFAULT region, so for a resource created in any other region the callback reads or writes the wrong store key and silently no-ops (statuses stuck at "creating"/"stopping", deferred deletes that never land).
AfterScoped closes both halves of that bug at once:
- fn receives a background context carrying region, so region-keyed store lookups inside the callback resolve the same record the request wrote;
- the scheduler key is scoped by region, so same-named resources in different regions cannot cancel or replace each other's pending transitions.
Callers pass the region resolved from the request context at schedule time (e.g. store.region(ctx)).
func (*Scheduler) Cancel ¶
Cancel cancels a pending transition by key. Returns true if a pending transition was found and cancelled.
func (*Scheduler) CancelScoped ¶
CancelScoped cancels a pending transition scheduled with AfterScoped.
func (*Scheduler) PendingCount ¶
PendingCount returns the number of currently scheduled transitions.