Skip to content
workers-go
Esc
navigateopen⌘Jpreview
On this page

Tail Workers

Consume another Worker's execution traces from Go with a Tail Worker.

A Tail Worker receives a batch of trace events for every invocation of a “producer” Worker. The exp/cloudflare/tail package registers the worker’s tail(events, env, ctx) handler and decodes each TraceItem.

Point a producer at the tail worker

There is no trigger key in the tail worker’s own wrangler.toml. Instead, add a tail_consumers entry to the producer worker’s wrangler.toml, naming the tail worker’s service:

tail_consumers = [{ service = "tail-worker" }]

Handle trace events

tail.Handle registers a func([]tail.TraceItem) error and blocks. Each TraceItem describes one producer invocation — ScriptName, Outcome, ExecutionModel, CpuTime, WallTime, plus Logs ([]TraceLog) and Exceptions ([]TraceException).

func main() {
	tail.Handle(func(items []tail.TraceItem) error {
		for _, item := range items {
			log.Printf("script=%s outcome=%s cpu=%.2fms wall=%.2fms",
				item.ScriptName, item.Outcome, item.CpuTime, item.WallTime)

			switch item.EventKind() {
			case "fetch":
				if fe, ok := item.FetchEvent(); ok {
					log.Printf("fetch %s %s", fe.Request.Method(), fe.Request.URL())
				}
			case "scheduled":
				if se, ok := item.ScheduledEvent(); ok {
					log.Printf("cron=%q", se.Cron)
				}
			case "queue":
				if qe, ok := item.QueueEvent(); ok {
					log.Printf("queue=%s batchSize=%d", qe.Queue, int(qe.BatchSize))
				}
			}
		}
		return nil
	})
}
  • item.Event is a discriminated union left as a js.Value. item.EventKind() infers the branch — "fetch", "jsrpc", "scheduled", "alarm", "queue", "email", "tail", or "hibernatableWebSocket" — and the matching typed accessor (FetchEvent(), ScheduledEvent(), AlarmEvent(), QueueEvent(), EmailEvent(), TailEvent(), JsRpcEvent(), HibernatableWebSocketEvent()) returns (*T, bool). connect and custom events carry no distinguishing properties, so they (and anything unrecognized) report EventKind() == "".
  • item.EventTime() decodes EventTimestamp (Unix ms) as a time.Time; a timestamp of 0 is reported as absent.
  • Returning an error logs the rejection but does not retry delivery.
  • Handle blocks; a worker that also serves other triggers should register those first and call a single blocking entry point such as workers.Serve instead.

Example project

_examples/tail-worker logs a summary of every trace event it receives.

Was this page helpful?