Cron Trigger
A minimal single-step workflow designed to run on a cron schedule, demonstrating how to set up time-based workflow triggers.
Workflow Definition
The workflow itself is simple – a single tick step that logs the current time. The cron schedule is configured separately when registering the workflow, not in the workflow JSON.
{
"name": "cron-trigger",
"version": "1.0",
"steps": [
{
"id": "tick",
"task": "tick",
"type": "normal",
"depends_on": []
}
]
}Worker Implementation
The handler prints the current UTC timestamp and completes. Each cron trigger creates a new workflow run, so the handler runs fresh each time.
package main
import (
"fmt"
"os"
"os/signal"
"time"
"github.com/danmestas/dagnats/worker"
"github.com/nats-io/nats.go"
)
func main() {
url := os.Getenv("NATS_URL")
if url == "" {
url = nats.DefaultURL
}
nc, err := nats.Connect(url)
if err != nil {
fmt.Fprintf(os.Stderr, "connect: %v\n", err)
os.Exit(1)
}
defer nc.Close()
w := worker.NewWorker(nc)
w.Handle("tick", handleTick)
fmt.Println("Worker ready. Waiting for tasks...")
w.Start()
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt)
<-sig
fmt.Println("\nShutting down...")
w.Stop()
}
// handleTick prints the current time and completes.
// Each cron invocation creates a fresh workflow run.
func handleTick(ctx worker.TaskContext) error {
now := time.Now().UTC().Format(time.RFC3339)
fmt.Printf("[tick] %s\n", now)
return ctx.Complete([]byte(now))
}Running the Example
Start the DagNats server:
dagnats serveIn a second terminal, start the worker:
go run ./examples/cron-trigger/In a third terminal, register the workflow and add a cron schedule:
dagnats workflow register examples/cron-trigger/workflow.json dagnats trigger create cron-trigger --cron "*/1 * * * *"This schedules the workflow to run every minute. The run input is a trigger envelope (
trigger,source,workflow_id,timestamp), not custom JSON.Watch the worker print timestamps every minute:
[tick] 2025-01-15T10:00:00Z [tick] 2025-01-15T10:01:00Z [tick] 2025-01-15T10:02:00ZRemove the schedule when done:
dagnats trigger list
dagnats trigger delete
## What's Happening
1. The `dagnats trigger create` command stores a cron trigger in the `triggers` KV bucket.
2. The server's scheduler, which ticks every 30 seconds, evaluates the expression and starts a new workflow run at each matching time.
3. Each run is independent -- the engine creates a fresh run, dispatches the `tick` step, and the handler executes.
4. The workflow definition stays simple. The scheduling concern is separate from the workflow logic.
This separation means any workflow can be cron-triggered without modification. You can add a cron schedule to the hello-world example, the retry-errors example, or any other workflow.
Key concepts demonstrated:
- **Cron schedules** are an operational concern, configured outside the workflow definition.
- **Each trigger creates a new run** -- there is no shared state between cron invocations.
- **Standard cron expressions** -- uses the familiar `* * * * *` format (minute, hour, day, month, weekday).
## Related
- [Cron Schedules](/docs/triggers/cron-schedules) -- cron configuration and expression reference