Suspending
Kontinue allows Executions to sleep or suspend by creation Suspensions.
Suspensions are Kubernetes resources that pause an Execution until a
condition is met. These are typically created when an Execution calls kontinue.Sleep() or kontinue.Suspend().
Suspensions are a key part of kontinue’s durability model. Because the suspension state is stored in Kubernetes, the Execution can be resumed by any worker after failures or restarts (and not restart the sleep from the beginning).
Sleep
Use kontinue.Sleep() to pause an Execution for a specified duration:
func DeployWorkflow(ktx *kontinue.ExecutionContext, args *DeployArgs) error {
// Deploy to staging
if err := deployToStaging(args); err != nil {
return err
}
// Wait 1 hour before deploying to production
if err := kontinue.Sleep(ktx, 1 * time.Hour); err != nil {
return err
}
// Deploy to production
return deployToProduction(args)
}
Unlike time.Sleep(), kontinue.Sleep() is replay-safe:
- The sleep duration is stored in a Suspension resource with a
resumeAttimestamp - If the worker crashes during the sleep, a new worker will resume from where it left off
- The Execution won’t re-sleep the full duration on resume
Sleeps can also be resumed early via the CLI or UI (see Resuming below).
Manual Suspend
Use kontinue.Suspend() to pause an Execution indefinitely until manually resumed:
func ApprovalWorkflow(ktx *kontinue.ExecutionContext, args *ApprovalArgs) error {
// Prepare the change
if err := prepareChange(args); err != nil {
return err
}
// Wait for manual approval
if err := kontinue.Suspend(ktx, &kontinue.SuspendOptions{}); err != nil {
return err
}
// Apply the approved change
return applyChange(args)
}
This is useful for:
- Human approval workflows
- Waiting for external events
- Pausing for manual verification steps
- Integration with external ticketing systems
Suspension Resource
When Sleep() or Suspend() is called, kontinue creates a Suspension resource:
apiVersion: kontinue.cloud/v1alpha1
kind: Suspension
metadata:
name: my-execution-sleep-abc123
ownerReferences:
- apiVersion: kontinue.cloud/v1alpha1
kind: Execution
name: my-execution
spec:
resumeAt: "2025-01-15T15:30:00Z" # Only for Sleep, nil for Suspend
status:
phase: Suspended
startedAt: "2025-01-15T14:30:00Z"
Suspension Phases
| Phase | Description |
|---|---|
Suspended | Waiting for resumeAt time or manual resume |
Completed | Suspension resolved, Execution can continue |
Canceled | Suspension was canceled |
The parent Execution tracks its suspended state in status.suspendedOn, which references
the Suspension resources it’s waiting on.
Resuming Suspensions
Using the CLI
Resume a specific suspension:
kontinue resume <suspension-name>
Resume all direct suspensions for an execution:
kontinue resume <execution-name>
Resume recursively (including child executions):
kontinue resume <execution-name> -r
Using the UI
In the kontinue UI:
- Navigate to the Execution details
- View the suspended state and pending Suspensions
- Click “Resume” to complete the Suspension
Using the API
// Resume a specific suspension
err := client.ResumeSuspension(ctx, suspension)
// Resume all suspensions for an execution
err := client.ResumeExecution(ctx, execution, &client.ResumeOptions{
Recursive: true, // Include child executions
})
When a Suspension is resumed:
- The Suspension’s phase changes to
Completed - The Execution detects the completion and continues
- The
suspendedOnreference is removed from the Execution status
Named Suspensions
For determinism, you can specify a custom step name:
// Using SleepNamed with explicit name
err := kontinue.SleepNamed(ktx, &kontinue.SleepOptions{
Duration: 1 * time.Hour,
StepOptions: kontinue.StepOptions{
Name: "wait-for-cooldown",
},
})
// Using Suspend with explicit name
err := kontinue.Suspend(ktx, &kontinue.SuspendOptions{
StepOptions: kontinue.StepOptions{
Name: "approval-gate",
},
})
This ensures the Suspension name is consistent across replays, even if execution order changes.