Running it

What to look at when something is wrong, and what gotick leaves behind in Redis.

On this page

The inspector

A built-in web UI: which calls are running, which step each one sits on, how long each took, what the error was, and how much of a sleep is left. It's a plain http.Handler that reads Redis directly, so it never has to reach a running worker — and because it lives in its own sub-package, never importing it costs your binary nothing at all. It can see every metadata value you passed in, so put authentication in front of it.

01Mount it on your mux

Folds into a service you already ship, and reuses the auth middleware you already have. Least work.

h, _ := ui.NewHandler(ui.Options{ RootPath: "/_gotick", Store: store.NewRedisStore(rdb), Auth: myAuthMiddleware,})mux.Handle("/_gotick/", h)
02Give it its own port

For a process with no HTTP server of its own, like net/http/pprof. Binding anywhere but loopback without credentials is refused rather than warned about.

go ui.ListenAndServe("127.0.0.1:6060", ui.Options{ Store: store.NewRedisStore(rdb),})
03Look from your terminal

Production is misbehaving: change no code, deploy nothing, point the CLI at Redis and look.

go run github.com/zbysir/gotick/cmd/gotick@latest ui \ -redis redis://localhost:6379/0

From the command line

gotick inspect prints one call's steps — status, retries, next run time, last error — and the metadata. It reads Redis too, so a stuck flow can be diagnosed without touching the running service. There's also a published container image if you'd rather run the inspector as its own service.

$ gotick inspect -redis redis://localhost:6379/0 9f2ac41b8e7d callId  9f2ac41b8e7dtasks   3 TASK        STATUS  RETRY  RUN AT                LAST ERRORsend-email  retry   1      2026-08-18T09:12:06Z  smtp timeoutstart       done    0      -                     -wait        sleep   0      2026-08-18T09:12:03Z  - metadata  order_id = ORD-1

What is stored, and for how long

Everything lives in the Redis you pointed gotick at. Cleanup is automatic; the numbers below are the defaults.

KeyWhat's in itLifetime
<callId>_statusOne field per step: status, retries, timings, last error7 days after the call reaches a terminal state
<callId>_metaYour metadata, memoised values, delivered signals7 days after the call reaches a terminal state
gotick:run:<callId>The run summary the inspector lists7 day TTL
gotick:runs, gotick:flow:<id>:runsSorted sets indexing runs by start timeTrimmed past the retention window, at most once every 10 minutes
gotick:flowsThe list of flow ids that have ever runKept — its size is bounded by how many flows you have
gotick:keys:<flowId>Your business key to callId, one hash per flowEach entry removed when its call finishes
asynq:*asynq's own queues and statsSuccessful tasks aren't kept; ones that exhaust retries are archived 90 days

Configuration

FieldWhat it does
RedisURL / RedisClientWhere Redis is. Pass a client of your own to reuse an existing pool.
QueueQueue namespace, default gotick. Change it to isolate one group of flows from another.
ConcurrencyHow many tasks one worker runs at once. Default 10.
DelayedTaskCheckIntervalHow often scheduled work is promoted to runnable — the real precision of every Sleep and every retry backoff. Default 500ms. Raising it saves Redis polling at the cost of looser wake-ups.
TaskCheckIntervalHow often an idle queue is checked for new work. Default 100ms.
ConsumeLegacyPerFlowQueuesUpgrading from the old queue-per-flow layout: turn it on so workers also drain the old queues, then turn it off once they're empty.

Render diagnostics