Two workers receive the same job after a lock expires.
Both are still alive.
Both can perform the side effect.
What protects correctness?
Longer lock? Idempotency key? DB constraint? Fencing token?
I’d rather make the side effect safe than trust the lock to save me.
You have a background job processing 50k records.
It crashes at record 47,000.
Would you rather:
restart the whole job,
checkpoint every N records,
make every operation idempotent,
or split it into smaller jobs?
I usually find the interesting part isn’t the queue configuration. It’s deciding what “resume safely” actually means.
One thing I don’t like in batch consumers:
increasing concurrency before understanding where the batch spends its time.
If 70% of the handler is waiting on DB connections or downstream I/O, adding more workers can just create more contention.
Measure the waiting before scaling the workers.
Node's event loop doesn't care that your "async" function is CPU-bound.
I've seen p99 climb because someone awaited a heavy JSON.parse and called it I/O.
If the loop is blocked, more workers won't help until you move that work off it.
Consumer lag isn't always a scale problem.
Sometimes the consumer is fine and the producer is batching into huge messages.
I'd check message size and deserialization cost before adding partitions.
@IamAroke Yes. Local tests never restart the pod mid-flight.
The cheap test is a rolling deploy while replaying the same request twice.
If dedupe lives in memory, one of them slips through.
A unique constraint on the idempotency key fails loudly instead.
NestJS modules feel clean until one provider needs half the app injected.
My first instinct: if a service pulls five modules, the boundary is wrong, not the DI config.
any isn't the only way TypeScript lies to you.
A wide interface every service "implements" does the same thing.
The checker passes.
The call sites still surprise you at runtime.
I'd rather keep the type narrow and make the boundary explicit.
@devXritesh Distributed transactions in payments rarely stay distributed transactions. You end up with a state machine, an outbox, and a reconciliation job — and when the PSP webhook and your API timeout disagree, the ledger is what you trust.
@BenjDicken Kafka's log is a WAL with consumers.
Postgres CDC flips it: you're a guest on someone else's WAL. Stall Debezium and the replication slot quietly eats the primary's disk.