Skip to content
Asikur Rahman
← All work

Contributed — backend services

Super Local Fans

A social CRM that turns customers into brand advocates — auto-posting, loyalty and content tooling across several social platforms. It runs as microservices with a micro-frontend, on Kubernetes.

01The problem

One of the backend jobs I worked on was scheduled publishing: fire a post to several social platforms at a future time, reliably, in a deployment where the service is running as multiple replicas. Naive scheduling in that environment either fires duplicates or wastes work.

02The constraint

A scheduled post had to fire exactly once at its time, survive replicas scaling up and down, and retry cleanly on failure — all within a Kubernetes microservices deployment observed through Sentry.

03What I built

Scheduled publishing runs on BullMQ delayed jobs backed by Redis: a scheduled post becomes one durable job that Redis holds until its time, then hands to a single worker. Retries and backoff are built in rather than hand-rolled.

The services are NestJS with a GraphQL (Apollo) API over PostgreSQL and Prisma, deployed on Kubernetes and instrumented with Sentry.

APISCHEDULE POSTREDISDELAYED JOBWORKERSINGLE OWNERSOCIAL PLATFORMSOCIAL PLATFORMSOCIAL PLATFORM
Architecture — Super Local Fans

04The decision

Options considered

Scheduling posts for a future time, in a service that runs as several replicas on Kubernetes, is where the naive answers fall apart.

  • AA cron per service — simple, until every replica fires the same cron and you get duplicate posts (or you bolt on leader election).
  • BPoll a 'due posts' table on an interval — works, but most queries find nothing and it never sits still.
  • CBullMQ delayed jobs backed by Redis — one durable job per scheduled post, owned by one worker.

Chose BullMQ delayed jobs.

The trade-off I accepted

A cron per replica duplicates work as you scale out, and polling a table burns queries doing nothing most of the time. BullMQ delayed jobs make a scheduled post a single durable unit: Redis holds it until it's due, exactly one worker picks it up, retries are part of the mechanism. The cost is another Redis-backed queue to run and reason about — but it was already the queue backbone for the services I worked on, so scheduled publishing rode on infrastructure that was there rather than adding a new mechanism.

05Stack

  • NestJS
  • GraphQL
  • Apollo
  • BullMQ
  • Redis
  • PostgreSQL
  • Prisma
  • Kubernetes
  • Sentry