Documentation
¶
Overview ¶
Package batch provides restartable, explicitly persisted job and step execution for Spice applications.
Index ¶
- Constants
- Variables
- type Attempt
- type AttemptSpec
- type BeginRequest
- type ContextFactory
- type Definition
- type ExecutionSnapshot
- type Failure
- type FailureKind
- type Job
- type MemoryStore
- func (store *MemoryStore) Begin(ctx context.Context, request BeginRequest) (Attempt, error)
- func (store *MemoryStore) Checkpoint(ctx context.Context, attempt Attempt, step string) error
- func (store *MemoryStore) Complete(ctx context.Context, attempt Attempt) error
- func (store *MemoryStore) Delete(ctx context.Context, definition Definition, instance string) error
- func (store *MemoryStore) Fail(ctx context.Context, failure Failure) error
- func (store *MemoryStore) Snapshot(ctx context.Context, definition Definition, instance string) (ExecutionSnapshot, bool, error)
- type Observation
- type Observer
- type Operation
- type PanicError
- type Result
- type Runner
- type SQLStatements
- type SQLStore
- func (store *SQLStore) Begin(ctx context.Context, request BeginRequest) (Attempt, error)
- func (store *SQLStore) Checkpoint(ctx context.Context, attempt Attempt, step string) error
- func (store *SQLStore) Complete(ctx context.Context, attempt Attempt) error
- func (store *SQLStore) Fail(ctx context.Context, failure Failure) error
- type SQLStoreOptions
- type Step
- type StepSpec
- type Store
Examples ¶
Constants ¶
const ( // SQLBeginOutcomeStarted identifies a newly inserted instance. SQLBeginOutcomeStarted = "started" // SQLBeginOutcomeResumed identifies a new attempt over retained checkpoints. SQLBeginOutcomeResumed = "resumed" // SQLBeginOutcomeComplete identifies an already-complete instance. SQLBeginOutcomeComplete = "complete" // SQLBeginOutcomeRunning identifies an unexpired active attempt. SQLBeginOutcomeRunning = "running" // SQLBeginOutcomeChanged identifies incompatible ordered steps. SQLBeginOutcomeChanged = "changed" // SQLBeginOutcomeOverflow identifies an exhausted signed SQL attempt number. SQLBeginOutcomeOverflow = "overflow" )
Variables ¶
var ( // ErrPanicked identifies a contained batch step panic. ErrPanicked = errors.New("batch step panicked") // ErrAlreadyRunning identifies an active attempt for the same job instance. ErrAlreadyRunning = errors.New("batch instance is already running") // ErrStaleAttempt identifies a transition for an inactive or old attempt. ErrStaleAttempt = errors.New("batch attempt is stale") // ErrDefinitionChanged identifies a persisted instance whose ordered steps // differ from the current job definition. ErrDefinitionChanged = errors.New("batch definition changed") // ErrCapacity identifies an in-process store at its configured instance // limit. ErrCapacity = errors.New("batch store capacity reached") )
Functions ¶
This section is empty.
Types ¶
type Attempt ¶
type Attempt struct {
// contains filtered or unexported fields
}
Attempt is immutable persisted restart metadata returned by a Store.
func NewAttempt ¶
func NewAttempt(spec AttemptSpec) (Attempt, error)
NewAttempt validates and freezes persisted restart metadata.
func (Attempt) CompletedSteps ¶
CompletedSteps returns a defensive copy of the durable completed prefix.
func (Attempt) Definition ¶
func (attempt Attempt) Definition() Definition
Definition returns the attempted job identity.
type AttemptSpec ¶
type AttemptSpec struct {
Definition Definition
Instance string
Number uint64
CompletedSteps []string
Complete bool
}
AttemptSpec is the inspectable input to NewAttempt.
type BeginRequest ¶
type BeginRequest struct {
Definition Definition
Instance string
Steps []string
}
BeginRequest asks a Store to atomically begin or resume one job instance.
type ContextFactory ¶
type ContextFactory func() (context.Context, context.CancelFunc)
ContextFactory creates one fresh bounded context for a failure transition after a step context has failed or been canceled.
type Definition ¶
Definition identifies one module-owned batch job.
type ExecutionSnapshot ¶
type ExecutionSnapshot struct {
Definition Definition
Attempt uint64
CompletedSteps []string
Running bool
Complete bool
LastFailureStep string
LastFailureKind FailureKind
}
ExecutionSnapshot is an immutable diagnostic view of one in-process execution. Instance identities are intentionally excluded.
type Failure ¶
type Failure struct {
Attempt Attempt
Step string
Kind FailureKind
}
Failure releases one active attempt for a later restart. It intentionally omits the application error and instance payload from durable metadata.
type FailureKind ¶
type FailureKind string
FailureKind is bounded durable failure metadata.
const ( // FailureError identifies a returned step or persistence error. FailureError FailureKind = "error" // FailureCanceled identifies caller cancellation. FailureCanceled FailureKind = "canceled" // FailurePanic identifies a contained step panic. FailurePanic FailureKind = "panic" )
type Job ¶
type Job struct {
// contains filtered or unexported fields
}
Job is an immutable ordered batch definition.
func NewJob ¶
func NewJob(definition Definition, specs []StepSpec) (*Job, error)
NewJob validates and freezes one ordered job.
func (*Job) Definition ¶
func (job *Job) Definition() Definition
Definition returns the job identity.
type MemoryStore ¶
type MemoryStore struct {
// contains filtered or unexported fields
}
MemoryStore is a concurrency-safe, capacity-bounded in-process Store.
State is not durable across process restarts. Use it for development, tests, and jobs whose restart state does not need to survive a process.
Example (Restart) ¶
package main
import (
"context"
"errors"
"fmt"
"time"
"github.com/spice-framework/spice/batch"
)
func main() {
store, err := batch.NewMemoryStore(100)
if err != nil {
panic(err)
}
loadAttempts := 0
job, err := batch.NewJob(
batch.Definition{
ID: "orders.import",
Module: "example.com/shop/orders",
},
[]batch.StepSpec{
{
ID: "extract",
Run: func(context.Context) error {
fmt.Println("extract")
return nil
},
},
{
ID: "load",
Run: func(context.Context) error {
loadAttempts++
fmt.Println("load")
if loadAttempts == 1 {
return errors.New("database unavailable")
}
return nil
},
},
},
)
if err != nil {
panic(err)
}
failureContext := func() (context.Context, context.CancelFunc) {
return context.WithTimeout(context.Background(), time.Second)
}
runner, err := batch.NewRunner(store, failureContext)
if err != nil {
panic(err)
}
first, firstErr := runner.Run(context.Background(), job, "2026-07-26")
second, secondErr := runner.Run(context.Background(), job, "2026-07-26")
third, thirdErr := runner.Run(context.Background(), job, "2026-07-26")
fmt.Println(first.Attempt, first.StepsCompleted, firstErr != nil)
fmt.Println(second.Attempt, second.StepsSkipped, secondErr)
fmt.Println(third.Attempt, third.AlreadyComplete, thirdErr)
}
Output: extract load load 1 1 true 2 1 <nil> 2 true <nil>
func NewMemoryStore ¶
func NewMemoryStore(capacity int) (*MemoryStore, error)
NewMemoryStore constructs an empty store with a fixed instance capacity.
func (*MemoryStore) Begin ¶
func (store *MemoryStore) Begin( ctx context.Context, request BeginRequest, ) (Attempt, error)
Begin atomically starts or resumes one execution attempt.
func (*MemoryStore) Checkpoint ¶
Checkpoint atomically records the next ordered step.
func (*MemoryStore) Complete ¶
func (store *MemoryStore) Complete( ctx context.Context, attempt Attempt, ) error
Complete atomically marks a fully checkpointed attempt complete.
func (*MemoryStore) Delete ¶
func (store *MemoryStore) Delete( ctx context.Context, definition Definition, instance string, ) error
Delete removes inactive execution state and releases capacity.
func (*MemoryStore) Fail ¶
func (store *MemoryStore) Fail(ctx context.Context, failure Failure) error
Fail atomically releases an active attempt for a later restart.
func (*MemoryStore) Snapshot ¶
func (store *MemoryStore) Snapshot( ctx context.Context, definition Definition, instance string, ) (ExecutionSnapshot, bool, error)
Snapshot returns a defensive diagnostic view when an execution exists.
type Observation ¶
type Observation struct {
Definition Definition
Operation Operation
Step string
Attempt uint64
Duration time.Duration
Resumed bool
Completed bool
Err error
Panicked bool
}
Observation contains bounded job metadata. Instance identities and application values are intentionally excluded.
type Observer ¶
type Observer func(context.Context, Observation)
Observer receives completed boundaries synchronously.
type PanicError ¶
type PanicError struct {
Definition Definition
Step string
}
PanicError reports a contained step panic without exposing its recovered value.
func (*PanicError) Unwrap ¶
func (err *PanicError) Unwrap() error
Unwrap supports errors.Is(err, ErrPanicked).
type Result ¶
type Result struct {
Attempt uint64
StepsSkipped int
StepsCompleted int
Resumed bool
AlreadyComplete bool
Duration time.Duration
}
Result summarizes one execution or restart.
type Runner ¶
type Runner struct {
// contains filtered or unexported fields
}
Runner executes one immutable job at a time through an explicit Store.
type SQLStatements ¶
SQLStatements supplies dialect-owned atomic statements for the batch persistence protocol. Statement text is trusted startup configuration, never request input.
type SQLStore ¶
type SQLStore struct {
// contains filtered or unexported fields
}
SQLStore implements Store through standard database/sql contracts.
func NewSQLStore ¶
func NewSQLStore( executor data.Executor, statements SQLStatements, options SQLStoreOptions, ) (*SQLStore, error)
NewSQLStore validates and freezes one driver-neutral SQL store. Construction performs no database operation.
func (*SQLStore) Begin ¶
Begin atomically inserts, resumes, or observes one persisted instance.
The statement arguments are job ID, module, instance, canonical JSON step IDs, current UTC time, and lease expiry. It must return exactly one row with outcome, positive attempt number, and JSON completed step IDs.
func (*SQLStore) Checkpoint ¶
Checkpoint atomically records the next step and renews the attempt lease.
Statement arguments are job ID, module, instance, attempt number, step, current UTC time, and lease expiry.
type SQLStoreOptions ¶
type SQLStoreOptions struct {
// AttemptLease is the maximum time an attempt remains exclusively active
// without a checkpoint. Steps may execute at least once when they outlive
// this lease and another runner resumes the instance.
AttemptLease time.Duration
// Clock supplies current time. Nil selects time.Now.
Clock func() time.Time
}
SQLStoreOptions controls durable attempt ownership.
type Step ¶
type Step struct {
// contains filtered or unexported fields
}
Step is one immutable job step.
type Store ¶
type Store interface {
Begin(context.Context, BeginRequest) (Attempt, error)
Checkpoint(context.Context, Attempt, string) error
Complete(context.Context, Attempt) error
Fail(context.Context, Failure) error
}
Store owns atomic attempt and checkpoint transitions. An implementation defines whether that state survives process restarts.