- Docs
- Reference
- TCP Protocol
- Overview
The wire protocol, documented.
A high-performance binary protocol on port 6789 by default. All messages use MessagePack encoding with length-prefixed framing, and pipelining lets the server process commands concurrently.
Wire Format
Section titled “Wire Format”Every message (request and response) is wrapped in a length-prefixed frame:
The framing protocol works as follows:
- The first 4 bytes are a big-endian unsigned 32-bit integer indicating the length of the MessagePack payload.
- The next N bytes are the MessagePack-encoded command or response object.
- Maximum frame size is 64 MB. Frames exceeding this limit cause the connection to be terminated.
Encoding Example
Section titled “Encoding Example”import { pack, unpack } from 'msgpackr';
// Encode a command into a framed messagefunction frameCommand(cmd: object): Uint8Array { const payload = pack(cmd); const frame = new Uint8Array(4 + payload.length); // Write length prefix (big-endian u32) frame[0] = (payload.length >> 24) & 0xff; frame[1] = (payload.length >> 16) & 0xff; frame[2] = (payload.length >> 8) & 0xff; frame[3] = payload.length & 0xff; frame.set(payload, 4); return frame;}
// Decode a framed response (skip the 4-byte length prefix)function decodeFrame(frame: Uint8Array): object { return unpack(frame.subarray(4));}Connection
Section titled “Connection”import { pack, unpack } from 'msgpackr';
const socket = await Bun.connect({ hostname: 'localhost', port: 6789, socket: { data(socket, data) { // Parse frames from data, then unpack each frame with msgpackr }, },});
// Send a commandconst cmd = pack({ cmd: 'Ping' });const frame = new Uint8Array(4 + cmd.length);frame[0] = (cmd.length >> 24) & 0xff;frame[1] = (cmd.length >> 16) & 0xff;frame[2] = (cmd.length >> 8) & 0xff;frame[3] = cmd.length & 0xff;frame.set(cmd, 4);socket.write(frame);Protocol Negotiation (Hello)
Section titled “Protocol Negotiation (Hello)”Clients should send a Hello command after connecting to report their protocol revision and discover server capabilities.
Request:
{ cmd: 'Hello', protocolVersion: 3, capabilities: ['pipelining', 'separate-job-name'] }Response:
{ ok: true, protocolVersion: 3, capabilities: ['pipelining', 'separate-job-name'], server: 'bunqueue', version: 'x.y.z' // Installed server package version}The current protocol version is 3. It supports pipelining and
separate-job-name. Revision 3 places job metadata in top-level job.name
and preserves job.data exactly as supplied. The server still accepts legacy
inputs with no top-level name: at that inbound boundary only, a string
data.name is decoded as the old embedded-name envelope.
Pipelining
Section titled “Pipelining”The server supports pipelining: clients can send multiple commands without waiting for each response. The server processes frames in parallel with a concurrency limit of 50 commands per connection, controlled by a semaphore.
To correlate responses with requests when pipelining, include a reqId field in each command. The server echoes reqId back in the corresponding response.
// Send two commands simultaneouslysocket.write(frameCommand({ cmd: 'PUSH', queue: 'emails', data: { to: 'a@b.com' }, reqId: '1' }));socket.write(frameCommand({ cmd: 'PUSH', queue: 'emails', data: { to: 'c@d.com' }, reqId: '2' }));
// Responses may arrive in any order - match by reqId// { ok: true, id: 'abc-123', reqId: '1' }// { ok: true, id: 'def-456', reqId: '2' }Authentication
Section titled “Authentication”When the server is configured with AUTH_TOKENS, all connections must authenticate before sending other commands. The Auth command is always permitted regardless of authentication state.
Request:
{ cmd: 'Auth', token: 'your-secret-token' }Response (success):
{ ok: true;}Response (failure):
{ ok: false, error: 'Invalid token' }If auth tokens are configured and a client sends any command before authenticating, the server responds with:
{ ok: false, error: 'Not authenticated' }Response Format
Section titled “Response Format”All responses include an ok boolean field. On success ok is true with command-specific data. On failure ok is false with an error string.
// Success{ ok: true, ...data, reqId?: string }
// Error{ ok: false, error: 'Error message', reqId?: string }Queue event frames
Section titled “Queue event frames”SubscribeEvents selects one queue for the current connection;
UnsubscribeEvents clears it without closing the socket. Both commands require
normal authentication and return a regular reqId-correlated response.
{ cmd: 'SubscribeEvents', queue: 'tasks', reqId: 'events-1' }{ ok: true, reqId: 'events-1' }
// Later, independently of command responses:{ type: 'event', event: { eventType: 'completed', queue: 'tasks', jobId: '...', timestamp: 0, data: { ok: true } } }
{ cmd: 'UnsubscribeEvents', reqId: 'events-2' }The unsolicited event envelope has no reqId. Pipelined clients must recognize
type: 'event' before correlating command responses. A new subscription on the
same connection replaces the previous queue. Slow subscribers are subject to
the normal per-connection write-buffer limit.
An optional eventTypes array (1 to 32 event type names of up to 64 characters;
null means no filter) limits the stream to
those types, which saves the broker the encoding and the client the decoding of
everything else. The bunqueue Worker subscribes this way for stalled only:
{ cmd: 'SubscribeEvents', queue: 'tasks', eventTypes: ['stalled'], reqId: 'events-3' }A broker older than the filter ignores eventTypes and sends every type, so
check event.eventType on the client side as well.
Connection Lifecycle
Section titled “Connection Lifecycle”When a TCP connection closes, the server automatically releases all jobs that were being processed by that client back to their queues. This uses retry logic with exponential backoff (up to 3 attempts) to ensure jobs are not left in an inconsistent state.
Rate Limiting
Section titled “Rate Limiting”Each connection is subject to server-side rate limiting. If exceeded, the server responds with:
{ ok: false, error: 'Rate limit exceeded' }Command Reference
Section titled “Command Reference”Every command object must include a cmd field. An optional reqId field can be included for request-response correlation (required for pipelining).
The commands are documented by family on the pages below, and the command summary links every command to its section.
| Page | Command families | Covers |
|---|---|---|
| Jobs | Core, Log, Lock, More Job | Add, claim, acknowledge and fail jobs; job logs; lock extension; more job transitions |
| Queries | Query | Read jobs, states, results, progress, child values and counts |
| Control & Limits | Control, Rate Limiting, Queue Config | Job and queue control, rate and concurrency limits, job groups, deduplication keys, stall and DLQ config |
| Dead Letter Queue | DLQ | Inspect, retry, purge and remove dead-letter entries; re-queue completed jobs |
| Cron | Cron | Create, update, list, read and delete cron schedules |
| Flows | Flow Dependency | Parent/child dependency commands used by FlowProducer |
| Monitoring | Monitoring, Dashboard | Health, protocol negotiation, stats, metrics, heartbeats and dashboard snapshots |
| Workers & Webhooks | Worker, Webhook | Worker registration and webhooks |
Queue Name Validation
Section titled “Queue Name Validation”Queue names must satisfy the following constraints:
- Not empty and at most 256 characters
- Only alphanumeric characters, underscores, dashes, dots, and colons:
[a-zA-Z0-9_\-.:]+
Job Data Limits
Section titled “Job Data Limits”Job data payloads are limited to 10 MB when serialized.
Command Summary
Section titled “Command Summary”| Category | Command | Description |
|---|---|---|
| Core | PUSH | Add a job to a queue |
PUSHB | Batch push multiple jobs | |
PUSHF | Atomically commit a flow graph | |
PULL | Pull next job (supports long poll and locks) | |
PULLB | Batch pull jobs | |
ACK | Acknowledge job completion | |
ACKB | Batch acknowledge | |
FAIL | Mark job as failed | |
| Query | GetJob | Get job by ID |
GetState | Get job state | |
GetResult | Get job result | |
GetJobs | List jobs with filtering | |
GetJobCounts | Count jobs by state | |
GetCountsPerPriority | Count jobs by priority | |
GetJobByCustomId | Look up job by custom ID | |
Count | Queued job count for a queue | |
GetProgress | Get job progress | |
GetChildrenValues | Get child job return values | |
GetQueueLimits | Read live queue rate/concurrency status | |
GetDeduplicationJobId | Resolve a queue-scoped deduplication key | |
| Control | Cancel | Cancel a job |
Progress | Update job progress | |
Update | Update job data | |
ChangePriority | Change job priority | |
Promote | Move delayed job to waiting | |
MoveToDelayed | Move active job to delayed | |
MoveToWaitingChildren | Park an active job for children | |
ChangeDelay | Change a delayed job’s delay | |
MoveToWait | Move a job back to waiting | |
PromoteJobs | Promote all delayed jobs in a queue | |
Discard | Move job to DLQ | |
WaitJob | Wait for job completion | |
ExtendLock | Extend a job lock | |
ExtendLocks | Extend job locks (batch) | |
RemoveDeduplicationKey | Release a queue-scoped deduplication key | |
RemoveJobDeduplicationKey | Release only a job-owned key | |
Pause | Pause a queue | |
Resume | Resume a queue | |
IsPaused | Check if queue is paused | |
Drain | Remove waiting/prioritized/delayed jobs | |
Obliterate | Remove all queue data | |
Clean | Remove old jobs | |
ListQueues | List all queues | |
| DLQ | Dlq | Get DLQ entries |
GetDlqStats | Get aggregate DLQ statistics | |
RetryDlq | Retry DLQ jobs | |
PurgeDlq | Clear DLQ | |
RemoveDlqJob | Permanently delete one DLQ job | |
RetryCompleted | Re-queue completed jobs | |
| Cron | Cron | Create/update cron schedule |
CronDelete | Delete cron schedule | |
CronList | List cron schedules | |
CronGet | Get cron schedule by name | |
| Monitoring | Ping | Health check |
Hello | Protocol negotiation | |
Stats | Server statistics | |
Metrics | Detailed metrics | |
TrimEvents | Trim one queue’s lifecycle journal | |
Prometheus | Prometheus-format metrics | |
StorageStatus | Get storage/disk health status | |
Heartbeat | Worker heartbeat | |
JobHeartbeat | Job heartbeat (stall prevention) | |
JobHeartbeatB | Batch job heartbeat | |
| Workers | RegisterWorker | Register a worker |
UnregisterWorker | Unregister a worker | |
ListWorkers | List workers | |
| Webhooks | AddWebhook | Register a webhook |
RemoveWebhook | Remove a webhook | |
ListWebhooks | List webhooks | |
SetWebhookEnabled | Enable/disable a webhook | |
| Rate | RateLimit | Set queue rate limit |
RateLimitClear | Clear queue rate limit | |
SetConcurrency | Set queue concurrency limit | |
ClearConcurrency | Clear concurrency limit | |
| Job groups | GetGroupJobsCount / GetGroupsJobsCount | Read grouped backlog |
GetGroupActiveCount | Read active jobs in one group | |
SetGroupRateLimit / GetGroupRateLimit / RemoveGroupRateLimit | Manage one group’s rate override | |
GetGroupRateLimitTtl | Read one group’s fixed-window TTL | |
SetGroupConcurrency / GetGroupConcurrency / RemoveGroupConcurrency | Manage one group’s concurrency override | |
PauseGroup / ResumeGroup / IsGroupPaused | Control and read one group’s pause state | |
RateLimitGroup | Install an immediate manual group deadline | |
| Config | SetStallConfig | Set per-queue stall config |
GetStallConfig | Get per-queue stall config | |
SetDlqConfig | Set per-queue DLQ config | |
GetDlqConfig | Get per-queue DLQ config | |
| Logs | AddLog | Add job log entry |
GetLogs | Get job logs | |
ClearLogs | Clear job logs | |
| Flow | UpdateParent | Update a child’s parent reference |
GetFailedChildrenValues | Failed children values | |
GetIgnoredChildrenFailures | Ignored children failures | |
RemoveChildDependency | Remove a child’s parent dependency | |
RemoveUnprocessedChildren | Remove unprocessed children | |
| Dashboard | DashboardOverview | Aggregated dashboard snapshot |
DashboardQueues | All queues with stats | |
DashboardQueue | Single queue detail | |
| System | CompactMemory | Trigger memory compaction |
| Events | SubscribeEvents | Stream one queue’s events on this connection |
UnsubscribeEvents | Stop this connection’s event stream | |
| Auth | Auth | Authenticate connection |