Guides

Sync Waves and Hooks

Order resource application with sync waves and lifecycle hooks

Sync Waves and Hooks — 📋 planned

Not implemented. There are no wardn.io/sync-wave or wardn.io/hook annotations in the operator today — all rendered objects are applied in a single pass. This guide describes the target behavior so manifests written with the annotations will work when it lands.

Complex applications often require resources to be applied in a specific order — databases before applications, migrations before pods, etc. Sync waves and hooks solve this.

Sync Waves

Resources are annotated with a wave number. Wardn applies waves in ascending order and waits for each wave to become healthy before proceeding:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  annotations:
    wardn.io/sync-wave: "1"     # applied first
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  annotations:
    wardn.io/sync-wave: "5"     # applied after postgres is healthy

Wave Ordering

Wave 0  →  Wave 1  →  Wave 2  →  ...  →  Wave N
  │           │           │                  │
  ▼           ▼           ▼                  ▼
apply      wait for    apply             wait for
           healthy                       healthy

Resources without a wave annotation default to wave 0.

Example: Database + App + Ingress

# Wave 0: Namespace and secrets
apiVersion: v1
kind: Namespace
metadata:
  name: my-app
  annotations:
    wardn.io/sync-wave: "0"
---
# Wave 1: Database
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  annotations:
    wardn.io/sync-wave: "1"
---
# Wave 2: Application
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  annotations:
    wardn.io/sync-wave: "2"
---
# Wave 3: Ingress (only after app is healthy)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
  annotations:
    wardn.io/sync-wave: "3"

Lifecycle Hooks

Hooks are resources that run at specific points in the sync lifecycle:

HookWhen It Runs
PreSyncBefore any resources are applied
SyncDuring the sync (alongside regular resources)
PostSyncAfter all resources are healthy
SyncFailOnly if the sync fails

Example: Database Migration

Run a migration Job before deploying the new application version:

apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration
  annotations:
    wardn.io/hook: PreSync
    wardn.io/hook-delete-policy: HookSucceeded
spec:
  template:
    spec:
      containers:
        - name: migrate
          image: myapp:v1.2.4
          command: ["./migrate", "up"]
      restartPolicy: Never

Hook Delete Policies

PolicyBehavior
HookSucceededDelete the hook resource after it succeeds
HookFailedDelete the hook resource after it fails
BeforeHookCreationDelete any previous hook resource before creating a new one

Sync Wave + Hook Combination

A typical deployment flow:

1. PreSync hook     → Run database migration
2. Wave 0           → Apply namespace, config
3. Wave 1           → Apply database (wait for healthy)
4. Wave 2           → Apply application (wait for healthy)
5. PostSync hook    → Send notification, run smoke tests

Failure Handling

If a sync wave fails to become healthy:

  1. The sync is marked as Failed
  2. Subsequent waves are not applied
  3. The SyncFail hook runs (if configured)
  4. A failure notification is sent (if configured)

On this page