Way to Prevent Message Ordering Issues in a High-Volume WhatsApp Automation System

Hello
I’m running a multi-tenant WhatsApp automation platform on n8n and have started seeing message ordering issues as traffic increases.
Webhook → Queue → Worker → Send WhatsApp Message
The problem is that multiple events for the same user can arrive almost simultaneously.
Under load, I sometimes see:
• Step 2 sent before Step 1
• Step 3 sent before Step 2
• Duplicate messages after retries
This becomes a bigger issue when multiple workers process jobs in parallel.
I’m considering:
• Per-user queues
• Redis-based locking
• Message sequencing IDs
• Queue partitioning by user_id

Describe the problem/error/question

How do you guarantee message order for the same user while still scaling horizontally?
Do you use locking, partitioning, or another pattern?
Any recommended architecture for maintaining ordering without killing throughput?

What is the error message (if any)?

Please share your workflow

(Select the nodes on your canvas and use the keyboard shortcuts CMD+C/CTRL+C and CMD+V/CTRL+V to copy and paste the workflow.)

Share the output returned by the last node

Information on your n8n setup

  • n8n version:
  • Database (default: SQLite):
  • n8n EXECUTIONS_PROCESS setting (default: own, main):
  • Running n8n via (Docker, npm, n8n cloud, desktop app):
  • Operating system:

Hi @Selena_Gloria

The most common solution is to partition or queue messages by user_id.

This ensures that all messages for the same user are processed one at a time, while different users can still be processed in parallel.

Recommended approach: Webhook → Queue by user_id → Worker → Send Message

You can also use a Redis lock:const lockKey = user:${userId};

to prevent multiple workers from sending messages to the same user at the same time.

Why this works
Maintains message order
Prevents duplicate sends
Still allows horizontal scaling

Just to clarify @Selena_Gloria, are jobs already being partitioned by user_id before they reach the worker, or is everything going through a single shared queue right now?

Also, do you need strict ordering for each user, or is it enough that jobs are processed in roughly the right order as long as retries are handled safely?

The Redis locking approach Niffzy mentioned is the right direction, but here’s how to actually wire it in n8n.

In a Code node right before your “Send WhatsApp Message” step, use the Redis node (or HTTP Request to your Redis instance) to run SET lock:user:{userId} 1 NX EX 30. If the SET returns null (lock already held), push the message payload to a Redis list (RPUSH queue:user:{userId} <payload>) and exit the workflow - do not send. After the message sends, run LRANGE queue:user:{userId} 0 0 to check if there are pending messages, process the next one, and then DEL lock:user:{userId}.

This gives you strict per-user ordering without a custom queue system - the Redis list acts as the per-user inbox, and the lock ensures only one worker sends for that user at a time. Set the TTL on the lock (EX 30 seconds) as a safety net so a failed execution doesn’t block the user permanently.

One thing to be careful about: n8n’s built-in Redis node doesn’t support arbitrary commands easily - you may need to use the HTTP Request node against your Redis REST API (Upstash works well here) or a Code node with the ioredis package if you’re self-hosted with NODE_FUNCTION_ALLOW_EXTERNAL=ioredis.