BullMQ
This page covers queue splitting for BullMQ, a Redis-backed persistent job queue. For the general concepts and the message filter reference shared by all queue services, see the Queue Splitting overview.
The word "queue" on this page refers to a BullMQ queue (backed by Redis lists, hashes, and sorted sets under the bull:<queue>:* key prefix).
Queue splitting for BullMQ requires mirrord operator 3.175.0 or later and mirrord CLI 3.223.0 or later.
How It Works
BullMQ stores jobs as Redis data structures: a wait list (bull:<queue>:wait), per-job hashes (bull:<queue>:<jobId>), and an ID counter (bull:<queue>:id). The mirrord operator's BullMQ forwarder dequeues jobs from the original wait list using BLPOP, inspects the job's data field (which must be valid JSON), and re-enqueues each job to the appropriate temporary queue based on the users' filters.
When the first mirrord BullMQ splitting session starts, the operator creates a temporary "main" queue for the deployed workload and patches the workload's queue-name environment variable to read from it. The forwarder then begins dequeuing from the original queue: jobs whose JSON data matches the user's filter are re-enqueued to a temporary per-session queue that the local application reads, and everything else is re-enqueued to the main queue.
If a second user starts a session on the same queue, the operator creates another per-session queue and adds the second user's filter to the routing logic. If the filters defined by two users both match some job, one of the users will receive the job at random.
When a session ends, the operator deletes the per-session queue's Redis keys. When all sessions end, the operator restores the workload to read from the original queue and deletes the main queue's Redis keys.
Enabling BullMQ Splitting in Your Cluster
Enable BullMQ splitting in the Helm chart
Enable the operator.bullmqSplitting setting in the mirrord-operator Helm chart.
Create a MirrordPropertyList
The operator needs to connect to your Redis instance to dequeue and re-enqueue jobs. Define the connection in a MirrordPropertyList (CustomResource) in the same namespace as the target workload (and the MirrordSplitConfig).
Supported properties:
url
Full Redis URL, e.g. redis://host:6379/0. Used as-is when present.
One of url or host
host
Redis hostname, used when url is absent.
One of url or host
port
Redis port, used with host.
No
6379
password
Password.
No
tls
Set to "true" to connect over TLS (rediss://).
No
false
db
Database index.
No
0
Create a MirrordSplitConfig
On operator installation with operator.bullmqSplitting enabled, a new CustomResource type is defined in your cluster - MirrordSplitConfig. Users with permissions to get CRDs can verify its existence with kubectl get crd mirrordsplitconfigs.queues.mirrord.metalbear.co.
Create a MirrordSplitConfig for the target workload. BullMQ uses kind: bullMq in queue entries.
The MirrordSplitConfig above says that:
It targets the deployment
order-workerin namespaceworkers.The Redis connection comes from the
bullmq-configMirrordPropertyList.The deployment consumes one BullMQ queue, whose name is in environment variable
BULLMQ_QUEUE.The queue can be referenced in a mirrord config under ID
orders.
Link the config to the deployed consumer
The MirrordSplitConfig is a namespaced resource. The target workload reference is specified with spec.targetRef:
apiVersion- API version of the Kubernetes workload (e.g.apps/v1).kind- type of the workload. Supported:Deployment,StatefulSet,Rollout.name- name of the workload.
Describe consumed queues
Each entry in the spec.queues list describes a BullMQ queue consumed by the workload:
id- arbitrary queue ID that developers reference from their mirrord config.kind- must bebullMq.clientConfig(optional) - name of aMirrordPropertyListwith the Redis connection. Can also be set once for all BullMQ queues withspec.clientConfigs.bullMq.queueConfig(optional) - name of aMirrordPropertyListwith forwarder tuning. Supported properties:dequeue_timeout- how longBLPOPwaits before retrying, in seconds (default:5).jq_time_limit- max milliseconds for jq filter evaluation per job (default:200).
appConfig.queue- the BullMQ queue name. Uses the same structure as other queue services (env,envLike,fallback,valueSelector,valuePattern,containers).
The mirrord operator can only read consumer's environment variables if they are either:
defined directly in the workload's pod template, with the value defined in
valueor invalueFromvia config map reference; orloaded from config maps using
envFrom.
Drain timeout
After the last session against a target ends, the operator keeps the split's temporary resources alive for the drain timeout so a new session can reuse them, then tears them down. It does not wait for unread jobs to be consumed first.
spec.drainTimeout on the MirrordSplitConfig
seconds
One split
Wins over the cluster-wide default.
drainTimeout
Behavior
unset (both)
Tear down as soon as the last session ends (same as 0).
0
Tear down immediately. Unread jobs may be lost.
N
Keep resources for up to N seconds, then tear down.
Setting a filter
For the full filter reference (queue_type, message_filter, jq_filter), see the overview. BullMQ uses queue_type: BullMQ.
BullMQ jobs carry their payload in a data field stored as a JSON string in the job hash. Filters match against the parsed JSON value of this data field. message_filter matches regexes against top-level JSON fields; jq_filter runs against the full parsed JSON.
Filtering on a top-level JSON field:
In the example above, the local application will receive only jobs whose data JSON has a top-level tenant field equal to test.
Filtering on the payload with jq_filter:
In the example above, the local application will receive only jobs whose data JSON contains "priority": "high".
Jobs whose data field is not valid JSON never match attribute or jq filters, so they are routed to the deployed (cluster) application.
Last updated
Was this helpful?

