Repository navigation
v0.3.0
Added
dashboardpackage: a password-protected web UI served as a plainhttp.Handler(Redis driver only, stdlib only, no new dependencies). Shows totals, per-day history, per-queue counts, job IDs, busy workers, retries, dead and deleted jobs, with Retry / Kill / Delete / Restore (single and batch, atomic Lua moves, nothing is hard-deleted). Mount it withdashboard.New(dashboard.Options{...}). An empty access token disables it (404 on every path); tokens must be at least 32 bytes. Seedocs/dashboard.md.- Tracking keys (Redis):
goqueue:queuesregistry,goqueue:stat:*processed/failed counters (global, daily, per queue),goqueue:process:*worker heartbeats and busy-job hashes,goqueue:deleted:<queue>deleted-job lists. Key names live inadapter/redis/keys.go.NewQueueregisters its queue withHSETNX(a producer never overwrites an existing dead key);Worker.Startregisters the consumer's real dead key withHSET, so a producer on the default DLQ cannot hide a consumer's custom DLQ list. - Dashboard actions return
{"Done","NotFound","Skipped"}.Skippedholds entries still at the source that cannot be moved (missing job name or unreadable data); the UI keeps their rows. examples/dashboard: runnable demo on miniredis.
Changed
- DLQ entries (Redis) now share one shape (
dlq.Entry): fieldqueue_nameis renamedqueue,job_nameis added, and the error is capped at 256 bytes.dlq.DecodeEntrystill reads legacyqueue_name. RedisDLQ.Pushnow usesRPUSH(newest entry at the tail instead of the head), keeps at most 1000 entries per queue and expires the list after 30 days.- Retry envelopes carry
error_messageandfailed_at(last failed attempt);Popexposes it asJobContext.LastError. Old envelopes without these fields still decode.
Breaking
RedisDLQordering: the newest dead job is now at the tail of the list, not the head. Anything that reads the list by index (LINDEX 0,LRANGE 0 n) now sees the oldest entries first.RedisDLQfield rename:queue_nameis nowqueue. Readers must usedlq.DecodeEntryor accept both names. Entries already stored withqueue_namestay readable throughDecodeEntry.
Upgrade notes
Legacy RedisDLQ lists (0.2.9 and older) were written with LPUSH (newest entry at the head) and never capped. 0.3.0 pushes with RPUSH and then LTRIM -1000 -1, which keeps the tail. On the first dead job after the upgrade:
- a legacy list longer than 1000 entries loses its newest entries (they sit at the head), and
- the remaining legacy entries show in reverse order in the dashboard (oldest as newest).
Before upgrading, with the old workers stopped:
- Find long lists:
redis-cli --scan --pattern 'dlq:*' | while read k; do echo "$(redis-cli LLEN "$k") $k"; done | sort -rn - Archive or drain every
dlq:*list longer than 1000 entries, for exampleredis-cli COPY dlq:<queue> dlq-archive:<queue>(Redis 6.2+) and process or drop the archive yourself. - Reverse each legacy list in place once, so the newest entry is at the tail. Run it exactly once per list (a second run reverses it back):
redis-cli EVAL "local v = redis.call('LRANGE', KEYS[1], 0, -1); redis.call('DEL', KEYS[1]); for i = #v, 1, -1 do redis.call('RPUSH', KEYS[1], v[i]) end; return #v" 1 dlq:<queue>Then start the 0.3.0 workers. Custom DLQ adapters that already RPUSH with a cap (for example fleetlery's) are unaffected.
Fixed
<queue>:metrics:ackno longer grows without bound:DequeueMetricsusesBRPOPinstead ofBRPOPLPUSHand never wrote an ack for metrics.MetricsAckQueueSuffixis deprecated. Clean up existing lists with:redis-cli --scan --pattern '*:metrics:ack' | xargs redis-cli del.
Full Changelog: v0.2.9...v0.3.0