This document describes the bidirectional communication infrastructure in Trigger.dev, covering both Socket.IO and native WebSocket implementations. Socket.IO is used primarily for worker coordination and control plane communication, while native WebSockets serve specific protocol requirements. For unidirectional real-time updates to the dashboard, see Realtime Updates and SSE.
Related pages:
Trigger.dev employs two distinct bidirectional communication mechanisms, each serving different architectural requirements:
| Technology | Use Case | Path | Applications |
|---|---|---|---|
| Socket.IO | Worker coordination, control plane | /socket.io/* | Coordinator, Supervisor, Webapp |
| Native WebSocket | Direct protocol communication | /ws | Webapp |
Both systems operate on the same Express HTTP server and share connection upgrade handling logic but serve fundamentally different purposes in the system architecture.
Sources: apps/webapp/server.ts1-269
Sources: apps/webapp/server.ts228-263 apps/webapp/app/entry.server.tsx234-235
Socket.IO is initialized in the application entry point and attached to the Express server during startup. The server instance is exported from the build module and made available to the HTTP server setup code.
The Socket.IO server is extracted from the build entry module and attached to the HTTP server:
Sources: apps/webapp/server.ts120-121 apps/webapp/server.ts225 apps/webapp/app/entry.server.tsx234
Socket.IO uses a Redis adapter (@socket.io/redis-adapter) to enable message broadcasting across multiple server instances in clustered deployments. This is critical for horizontal scaling where Socket.IO clients may connect to different server instances.
Package Dependencies:
socket.io: 4.7.4socket.io-adapter: 2.5.4@socket.io/redis-adapter: 8.3.0Environment Configuration:
| Variable | Default | Purpose |
|---|---|---|
PUBSUB_REDIS_HOST | Falls back to REDIS_HOST | Redis host for pub/sub |
PUBSUB_REDIS_PORT | Falls back to REDIS_PORT | Redis port |
PUBSUB_REDIS_USERNAME | Falls back to REDIS_USERNAME | Authentication username |
PUBSUB_REDIS_PASSWORD | Falls back to REDIS_PASSWORD | Authentication password |
PUBSUB_REDIS_TLS_DISABLED | false | Whether to disable TLS |
PUBSUB_REDIS_CLUSTER_MODE_ENABLED | 0 | Enable Redis cluster mode |
Sources: apps/webapp/package.json110 apps/webapp/package.json200-201 apps/webapp/app/env.server.ts207-237 pnpm-lock.yaml432-434
The native WebSocket implementation uses the ws library (version 8.12.0) for direct WebSocket protocol support without the Socket.IO protocol overhead.
The WebSocket server is instantiated separately from Socket.IO:
The handlers are exported from a separate module:
apps/webapp/app/entry.server.tsx235
Sources: apps/webapp/server.ts12 apps/webapp/server.ts121 apps/webapp/app/entry.server.tsx235 apps/webapp/package.json213
Both Socket.IO and native WebSocket connections begin as HTTP requests that are upgraded to the WebSocket protocol. The Express server implements a custom upgrade event handler to route connections based on the request path.
The upgrade handler is registered on the Express HTTP server after removing default listeners added by Socket.IO:
Key Routing Logic:
/socket.io/*): Delegates to Engine.IO's handleUpgrade method/ws): Delegates to ws library's handleUpgrade methodSources: apps/webapp/server.ts226-263
The webapp supports optional clustering to distribute load across multiple CPU cores. When clustering is enabled, each worker process runs its own Express server with Socket.IO and WebSocket instances.
Environment Variables:
| Variable | Purpose |
|---|---|
ENABLE_CLUSTER | Set to "1" to enable clustering |
WEB_CONCURRENCY or CLUSTER_WORKERS | Number of worker processes (defaults to CPU count) |
GRACEFUL_SHUTDOWN_TIMEOUT | Milliseconds to wait for graceful shutdown (default: 30000) |
The primary process:
Each worker process sets a descriptive title for easier identification in process monitoring tools:
Sources: apps/webapp/server.ts15-90 apps/webapp/server.ts109-111
The actual Socket.IO and WebSocket connection handling logic is implemented in separate modules that are referenced but not directly visible in the provided source files.
| Module | Export | Purpose |
|---|---|---|
./v3/handleSocketIo.server | socketIo: { io: IoServer } | Socket.IO server instance and handlers |
./v3/handleWebsockets.server | wss: WebSocketServer | WebSocket server instance and handlers |
These modules are exported from the entry server and consumed by the main server setup:
apps/webapp/app/entry.server.tsx234-235
The server extracts these exports from the build module:
Sources: apps/webapp/app/entry.server.tsx234-235 apps/webapp/server.ts115 apps/webapp/server.ts120-121
Socket.IO is not limited to the webapp; it's also used in other applications within the Trigger.dev architecture:
Coordinator App apps/coordinator/package.json:
socket.io: 4.7.4Supervisor App apps/supervisor/package.json:
socket.io: 4.7.4Sources: pnpm-lock.yaml99-125 pnpm-lock.yaml168-197
The project includes a patch for [email protected], which is the underlying protocol parser for Socket.IO. This patch modifies the parsing behavior to address specific issues.
Patch Location: patches/[email protected]
Patch Reference in Dependencies:
This patch is automatically applied during pnpm install and affects all Socket.IO communication in the system.
Sources: pnpm-lock.yaml26-28 package.json79
The Express HTTP server is configured with specific settings to optimize Socket.IO and WebSocket communication:
The server implements graceful shutdown for both HTTP and WebSocket connections:
In cluster mode, the primary process coordinates graceful shutdown across all workers:
Sources: apps/webapp/server.ts201-223 apps/webapp/server.ts45-57
The upgrade handler includes error handling for socket-level failures:
Invalid upgrade requests receive explicit error messages:
Sources: apps/webapp/server.ts231-255
The Docker build includes all necessary dependencies for Socket.IO and WebSocket support:
The production image includes all runtime dependencies, including Socket.IO and WebSocket libraries, as specified in the production dependencies phase.
The server listens on a configurable port:
Sources: docker/Dockerfile1 docker/Dockerfile105 apps/webapp/server.ts117
The Trigger.dev Socket.IO and WebSocket infrastructure provides:
The implementation separates transport concerns (handled in server.ts) from business logic (handled in handleSocketIo.server.ts and handleWebsockets.server.ts), providing a clean separation of concerns and maintainable architecture.
Sources: apps/webapp/server.ts1-269 apps/webapp/app/entry.server.tsx234-235 apps/webapp/package.json1-290
Refresh this wiki