0%
[/]JOSHIDEAS
SYSTEM_BLOG
TIME:13:33:11
STATUS:ONLINE
~/blog/distributed-print-system-architecture
$cat distributed-print-system-architecture.md_

Building a Distributed Print System with Node.js and WebSockets

#Node.js#WebSocket#IoT

# Building a Distributed Print System with Node.js and WebSockets

Enterprise label printing demands reliability at scale. This architecture handles thousands of print jobs across multiple locations with automatic printer discovery and intelligent failover.

## System Overview

The print system consists of three layers:

  1. >API Gateway - Receives print requests
  2. >Job Orchestrator - Routes and manages jobs
  3. >Print Workers - Execute actual printing
┌─────────────┐     ┌───────────────┐     ┌──────────────┐
│   Client    │────▶│   Gateway     │────▶│  Orchestrator│
└─────────────┘     └───────────────┘     └──────────────┘
                                                  │
                    ┌─────────────────────────────┼─────────────────────────────┐
                    │                             │                             │
                    ▼                             ▼                             ▼
            ┌──────────────┐             ┌──────────────┐             ┌──────────────┐
            │   Worker 1   │             │   Worker 2   │             │   Worker N   │
            │  (Warehouse) │             │  (Shipping)  │             │   (Office)   │
            └──────────────┘             └──────────────┘             └──────────────┘

## Auto-Discovery Protocol

Workers announce themselves on startup via UDP broadcast:

javascript
const dgram = require('dgram'); const socket = dgram.createSocket('udp4'); function announceWorker(workerId, capabilities) { const message = Buffer.from(JSON.stringify({ type: 'WORKER_ANNOUNCE', workerId, capabilities, timestamp: Date.now() })); socket.setBroadcast(true); socket.send(message, 0, message.length, 5000, '255.255.255.255'); }

### Discovery Response

The orchestrator listens for announcements and maintains a registry:

javascript
const workers = new Map(); socket.on('message', (msg, rinfo) => { const data = JSON.parse(msg.toString()); if (data.type === 'WORKER_ANNOUNCE') { workers.set(data.workerId, { ...data, address: rinfo.address, lastSeen: Date.now() }); } });

## WebSocket Communication

Real-time job dispatch uses WebSockets for bidirectional communication:

javascript
const WebSocket = require('ws'); class PrintWorker { constructor(orchestratorUrl, workerId) { this.ws = new WebSocket(orchestratorUrl); this.workerId = workerId; this.activeJobs = new Map(); this.ws.on('message', this.handleMessage.bind(this)); } handleMessage(data) { const message = JSON.parse(data); switch (message.type) { case 'JOB_ASSIGN': this.processJob(message.job); break; case 'JOB_CANCEL': this.cancelJob(message.jobId); break; case 'STATUS_REQUEST': this.reportStatus(); break; } } }

## Smart Retry Logic

Print failures are inevitable. The retry system handles them gracefully:

Failure TypeRetry StrategyMax Attempts
Network TimeoutExponential backoff5
Paper JamImmediate retry3
Offline PrinterRoute to backup1
Invalid DataNo retry (fail fast)0
javascript
async function executeWithRetry(job, options = {}) { const { maxAttempts = 3, backoffMs = 1000 } = options; for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await executePrintJob(job); } catch (error) { if (!isRetryable(error) || attempt === maxAttempts) { throw error; } const delay = backoffMs * Math.pow(2, attempt - 1); await sleep(delay); } } }

## Brother Raster Protocol Integration

Label printing uses the Brother raster protocol for thermal printers:

javascript
const net = require('net'); function sendLabelToPrinter(printerIp, labelData) { return new Promise((resolve, reject) => { const socket = new net.Socket(); socket.connect(9100, printerIp, () => { // Initialize printer socket.write(Buffer.from([0x1B, 0x40])); // ESC @ // Set media type socket.write(Buffer.from([0x1B, 0x69, 0x7A, ...])); // Send raster data socket.write(labelData); // End job socket.write(Buffer.from([0x1A])); socket.end(); }); socket.on('close', resolve); socket.on('error', reject); }); }

## Monitoring and Metrics

Every component emits metrics for observability:

  • >Job Latency - Time from submission to completion
  • >Queue Depth - Pending jobs per worker
  • >Error Rates - Failures by type and printer
  • >Throughput - Jobs per minute per location

## Conclusion

Distributed printing requires careful orchestration of discovery, routing, and failure handling. This event-driven architecture scales horizontally while maintaining reliability through smart retry logic and real-time communication.