Skip to content

Worker: silent shard-stuck when worker.run() fails silently during startup #412

Description

@ayushjhanwar-png

Summary

apps/worker/src/boot-workers.ts calls worker.run() for each GroupMQ event shard without await or .catch(). If the underlying redis.duplicate() blocking-client setup silently fails for a specific shard (e.g., a transient Redis blip during a rolling-deploy connection burst), the promise rejects with no handler and the worker enters GroupMQ's exponential backoff sleep forever. The pod appears healthy, "Started worker for events_N" is logged, but that shard never consumes.

Impact (real production incident, 2026-07-09)

  • 3 of 24 event shards silently stopped consuming after a rolling deploy
  • 570K jobs accumulated in Redis over ~2 hours before it was noticed
  • Redis memory 2% → 22% (~9 GB)
  • Cascaded to API pod OOM from increased Redis load
  • Zero error logs anywhere in the worker code path
  • Manual rolling-restart of the StatefulSet resolved it (fresh redis.duplicate() succeeded on the second try)

Root cause

apps/worker/src/boot-workers.ts around line 170:

worker.on('completed', markEventsActivity);
worker.on('drained', markEventsActivity);

worker.run();                                                  // ← unawaited, no .catch()
workers.push(worker);
logger.info({ concurrency }, `Started worker for ${queueName}`);

Right below this, the Kafka consumer startup is handled correctly:

startKafkaEventsConsumer()
  .then((h) => { handle = h; })
  .catch((err) => { ... });

So the GroupMQ path is inconsistent with how Kafka is handled.

Introduced in da59622d (2025-11-15, "fix: overall perf improvements"). Has been latent for ~8 months.

Suggested fix

.catch() on worker.run() — crash the pod on startup failure so k8s restarts with fresh Redis connections. Also add a worker.on('error', ...) listener so runtime errors on the blocking client are visible.

Happy to open a PR — will follow up shortly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions