Game logic worker for managing rooms and state in multiplayer games
npm install @roomkit/workerWorker server for the RoomKit framework - manages room state and game logic.
``bash`
npm install @roomkit/worker @roomkit/core
- 🎮 Room Management - Create and manage game rooms with state synchronization
- 🔄 Message Handling - Type-safe message handling with RoomKit protocol
- 💾 State Persistence - Optional room state persistence to Redis
- 🔌 Hot Reload - Seamless room migration between workers
- ��️ Circuit Breaker - Protection against overload with graceful degradation
- 📊 Metrics - Built-in Prometheus metrics
- ⚡ High Performance - Optimized for low-latency multiplayer games
`typescript
import { Room } from '@roomkit/worker';
interface GameState {
players: Map
score: number;
}
class GameRoom extends Room
maxClients = 4;
onCreate(options: any) {
this.setState({
players: new Map(),
score: 0,
});
}
onJoin(client: Client, options?: any) {
this.state.players.set(client.sessionId, {
name: options.name,
x: 0,
y: 0,
});
this.broadcast('player-joined', { id: client.sessionId });
}
onMessage(client: Client, type: string, payload: any) {
if (type === 'move') {
const player = this.state.players.get(client.sessionId);
if (player) {
player.x = payload.x;
player.y = payload.y;
this.broadcast('player-moved', { id: client.sessionId, ...payload });
}
}
}
onLeave(client: Client, consented: boolean) {
this.state.players.delete(client.sessionId);
this.broadcast('player-left', { id: client.sessionId });
}
}
`
`typescript
import { createWorker, Room } from '@roomkit/worker';
class GameRoom extends Room
const worker = await createWorker({
redis: 'redis://localhost:6379',
rooms: [
{ name: 'game', room: GameRoom }
],
admin: {
port: 28200
},
});
await worker.listen();
console.log(\Worker listening on admin port \${worker.adminPort}\);`
`typescript
// Option 1: URL string
redis: 'redis://:password@localhost:6379/0'
// Option 2: Object
redis: {
host: 'localhost',
port: 6379,
password: 'your-password',
db: 0
}
`
`typescript`
rooms: [
{
name: 'lobby', // Room type name
room: LobbyRoom // Room class
},
{
name: 'game',
room: GameRoom
},
]
`typescript`
circuitBreaker: {
maxRooms: 1000, // Max rooms per worker (default: 1000)
maxPendingRequests: 100, // Max pending room creation requests (default: 100)
enabled: true, // Enable circuit breaker (default: true)
failureThreshold: 5, // Failures before opening (default: 5)
successThreshold: 2, // Successes before closing (default: 2)
timeout: 10000, // Timeout in ms (default: 10000)
resetTimeout: 30000, // Reset timeout in ms (default: 30000)
}
`typescript`
persistence: {
enabled: true, // Enable persistence (default: false)
saveInterval: 5000, // Auto-save interval in ms (default: 5000)
loadOnCreate: true, // Load state on room creation (default: true)
}
`typescript`
admin: {
port: 28200, // Admin API port (default: 28200)
enabled: true // Enable admin API (default: true)
}
`typescript
import { createWorker, Room } from '@roomkit/worker';
import { LobbyRoom } from './rooms/LobbyRoom';
class GameRoom extends Room
const worker = await createWorker({
// Optional: Custom worker ID (auto-generated if not provided)
id: 'worker-1',
// Redis configuration (required)
redis: {
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT || '6379'),
password: process.env.REDIS_PASSWORD,
},
// Room definitions (required)
rooms: [
{ name: 'lobby', room: LobbyRoom },
{ name: 'game', room: GameRoom },
],
// Circuit breaker configuration
circuitBreaker: {
maxRooms: 1000,
maxPendingRequests: 100,
enabled: true,
failureThreshold: 5,
successThreshold: 2,
timeout: 10000,
resetTimeout: 30000,
},
// State persistence
persistence: {
enabled: true,
saveInterval: 5000,
loadOnCreate: true,
},
// Admin API
admin: {
port: 28200,
enabled: true,
},
});
// Start the worker
await worker.listen();
// Graceful shutdown
process.on('SIGTERM', async () => {
await worker.close();
process.exit(0);
});
`
`typescript
class MyRoom extends Room
// Called when room is created
onCreate(options: any) {
this.setState({ ... });
}
// Called when a client joins
onJoin(client: Client, options?: any) {
// Add player to state
}
// Called when client sends a message
onMessage(client: Client, type: string, payload: any) {
// Handle game logic
}
// Called when a client leaves
onLeave(client: Client, consented: boolean) {
// Remove player from state
}
// Called before room is destroyed
onDispose() {
// Cleanup resources
}
}
`
`typescript
// Broadcast to all clients
this.broadcast('event-type', { data: 'value' });
// Broadcast to all except one
this.broadcast('event-type', { data: 'value' }, { except: client });
// Send to specific client
client.send('event-type', { data: 'value' });
`
`typescript
// Set initial state
this.setState({ score: 0, players: new Map() });
// Update state (triggers automatic sync to clients)
this.state.score += 10;
this.state.players.set(id, player);
// Lock for atomic updates
this.lock.acquire('update-score', async () => {
this.state.score += 10;
});
`
`typescript
// Set custom metadata (visible in lobby)
this.setMetadata({
mapName: 'Forest',
difficulty: 'Hard'
});
// Set if room is private
this.setPrivate(true);
`
The worker supports basic environment variables for infrastructure configuration:
`bashRedis (infrastructure)
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=your-password
Admin API
$3
`bash
GET http://localhost:28200/health
`$3
`bash
GET http://localhost:28200/metrics
`$3
`bash
GET http://localhost:28200/admin/rooms
`Docker
`dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 28200
CMD ["node", "worker.js"]
``bash
docker run -p 28200:28200 \
-e REDIS_HOST=redis \
-e REDIS_PORT=6379 \
my-worker
`Production Deployment
$3
Run multiple worker instances:
`bash
Worker 1
node worker.js --id worker-1Worker 2
node worker.js --id worker-2Workers register automatically via Redis
``- Monitor room count, client count, message rate
- Set up alerts for circuit breaker triggers
- Track room creation/disposal rates
1. Set maxRooms based on your server capacity
2. Enable persistence for important game state
3. Use circuit breaker to prevent overload
4. Implement proper cleanup in onDispose()
5. Handle errors gracefully in onMessage()
MIT