bunqueue Architecture: Sharded Job Queue System Design for Bun
architecture · overview
Inside the bunqueue architecture.
bunqueue is a high-performance job queue built for Bun with SQLite persistence. This section covers the internal architecture, data flows, and design decisions.
System Overview
Section titled “System Overview”System overviewclient, server, persistence
client layer
Queue.add() TcpPool
→
Worker.process() TcpPool
↓ msgpack over TCP :6789
server layer
QueueManager
N shards auto-detected: Shard 0, Shard 1, ... Shard N
jobIndex
completedJobs
customIdMap
jobResults
↓
persistence layer
WriteBuffer
→
SQLite WAL mode
background tasks
Scheduler
Stall detection
DLQ maintenance
Cleanup
Layered Architecture
Section titled “Layered Architecture”| Layer | Purpose | Key Components |
|---|---|---|
| Client | SDK for applications | Queue, Worker, FlowProducer, TcpPool |
| Server | Request handling | TcpServer, HttpServer, Handlers |
| Application | Orchestration | QueueManager, Operations, Managers |
| Domain | Business logic | Shard, PriorityQueue, DLQ |
| Infrastructure | External systems | SQLite, S3 Backup, Scheduler |
| Shared | Utilities | Hash, Lock, LRU, MinHeap |
Architecture Sections
Section titled “Architecture Sections”| Section | Description |
|---|---|
| Client SDK | TCP connection, job submission, worker processing |
| Domain Layer | Sharding, priority queues, DLQ logic |
| Application Layer | Operations flow, background tasks |
| Persistence | SQLite configuration, write buffering, servers |
| Data Structures | Core algorithms and complexities |
| TCP Protocol | Wire format and commands |
| Cron Scheduler | Event-driven scheduling, timezone support, persistence |
Key Design Decisions
Section titled “Key Design Decisions”Dynamic Shard Architecture
Section titled “Dynamic Shard Architecture”Jobs are distributed across N independent shards (auto-detected from CPU cores) using FNV-1a hash:
SHARD_COUNT = calculateShardCount() // Power of 2, based on CPU cores, max 64SHARD_MASK = SHARD_COUNT - 1shardIndex = fnv1a(queueName) & SHARD_MASK // src/shared/hash.ts
// Examples: 4 cores → 4 shards, 10 cores → 16 shards, 64+ cores → 64 shardsBenefits:
- Auto-scales with hardware (power of 2, max 64)
- Parallel operations on different queues
- Reduced lock contention
- Bitwise AND faster than modulo
4-ary Priority Queue
Section titled “4-ary Priority Queue”Each shard contains a 4-ary heap instead of binary:
- Better cache locality (children fit in cache line)
- Fewer tree levels (8 vs 16 for 65k items)
- O(log₄ n) operations
Write Buffer
Section titled “Write Buffer”Jobs batch before SQLite write:
Buffer 100 jobs
→
Multi-row INSERT ~100k jobs/sec
Flushes after 10ms or when 100 jobs are buffered, whichever comes first.
- Buffered: ~100k jobs/sec, up to 10ms loss risk
- Durable: ~10k jobs/sec, immediate persistence
Lazy Deletion
Section titled “Lazy Deletion”Heap entries use generation tracking:
Remove: Delete from index (O(1)), mark heap entry stalePop: Skip entries where generation != currentCompact: Rebuild when >20% staleLock Hierarchy
Section titled “Lock Hierarchy”Acquire in order to prevent deadlocks:
1. jobIndex (read-only)2. completedJobs (check before lock)3. shardLocks[N]4. processingLocks[N]Memory Bounds
Section titled “Memory Bounds”| Collection | Limit | Eviction |
|---|---|---|
| completedJobs | 50,000 | FIFO batch |
| jobResults | 10,000 | LRU |
| jobLogs | 10,000 | LRU |
| customIdMap | 50,000 | LRU |
| DLQ per queue | 10,000 | FIFO |
Performance Summary
Section titled “Performance Summary”| Operation | Complexity |
|---|---|
| PUSH | O(log₄ n) |
| PULL | O(log₄ n) |
| ACK | O(1) |
| ACK batch | O(shards) |
| Job lookup | O(1) |
| Stats | O(1) |