mirror of
https://github.com/hcengineering/platform.git
synced 2026-08-25 13:52:24 +02:00
4.3 KiB
4.3 KiB
Quick Start: HA Stateless Containers
5-Minute Guide
What is it?
A feature that lets multiple agents compete to manage the same container UUID. The first agent wins, and others automatically take over if it fails.
When to use it?
- You need leader election
- You want only one instance of a service running
- You need automatic failover
- You want HA without external coordination services
Basic Example
import { AgentImpl } from '@hcengineering/network-core'
import { createNetworkClient } from '@hcengineering/network-client'
// 1. Create your container
class MyService implements Container {
constructor(readonly uuid: ContainerUuid) {}
async request(operation: string): Promise<any> {
return { status: 'active', uuid: this.uuid }
}
async terminate(): Promise<void> {
console.log('Service stopped')
}
// ... other required methods
}
// 2. Create agents (both will try to register same UUID)
const sharedUUID = 'my-service-001' as ContainerUuid
// Agent 1 (Primary)
const agent1 = new AgentImpl('agent-1', {})
const service1 = new MyService(sharedUUID)
agent1.addStatelessContainer(
sharedUUID,
'my-service' as ContainerKind,
'service://agent1/service-001' as ContainerEndpointRef,
service1
)
// Agent 2 (Standby)
const agent2 = new AgentImpl('agent-2', {})
const service2 = new MyService(sharedUUID)
agent2.addStatelessContainer(
sharedUUID,
'my-service' as ContainerKind,
'service://agent2/service-001' as ContainerEndpointRef,
service2
)
// 3. Connect and register
const client = createNetworkClient('localhost:3737')
await client.waitConnection()
await client.register(agent1) // ✅ Accepted
await client.register(agent2) // ❌ Rejected (agent1 already owns it)
// 4. Failover happens automatically
await agent1.terminate(sharedUUID) // Agent1 stops
// After ~100ms, agent2 automatically takes over
Key Methods
// Add a stateless container to agent
agent.addStatelessContainer(uuid, kind, endpoint, container)
// Remove from tracking (if needed)
agent.removeStatelessContainer(uuid)
// Register with network (handles conflicts automatically)
await client.register(agent)
// Monitor for failover events
client.onUpdate(async (event) => {
for (const c of event.containers) {
if (c.event === NetworkEventKind.removed) {
console.log('Container removed - failover in progress')
}
}
})
What Happens?
- Both agents register → First one is accepted, second is rejected
- Rejected agent → Terminates its container instance
- Active container fails → Network broadcasts removal event
- Standby agents → Automatically re-register (100ms delay)
- First standby wins → Takes over as new active instance
Common Patterns
Leader Election
const leaderId = `cluster-${clusterId}-leader` as ContainerUuid
agent.addStatelessContainer(leaderId, 'leader', endpoint, leaderService)
// First agent to register becomes leader
Singleton Service
const singletonId = 'migration-service' as ContainerUuid
agent.addStatelessContainer(singletonId, 'migration', endpoint, migrationService)
// Only one instance will run migrations
Active-Standby Database
const dbId = 'database-primary' as ContainerUuid
agent.addStatelessContainer(dbId, 'database', endpoint, databaseReplica)
// Primary serves writes, standby automatically promotes on failure
Gotchas
❌ Don't use different UUIDs on different agents (they won't compete) ✅ Do use the same UUID across all HA agents
❌ Don't forget to handle termination of rejected containers ✅ Do let the agent.register() method handle it automatically
❌ Don't expect instant failover (there's a ~100ms delay) ✅ Do design for eventual consistency
Testing
# Terminal 1: Start network
cd pods/network-pod && rushx dev
# Terminal 2: Run example
npx ts-node examples/ha-stateless-container-example.ts
Next Steps
- Read full docs:
docs/HA_STATELESS_CONTAINERS.md - See working example:
examples/ha-stateless-container-example.ts - Run tests:
cd packages/core && rushx test
Questions?
- How long is failover? ~100ms by default
- Can I have 3+ standbys? Yes, first to re-register wins
- Does state transfer? No, containers are stateless
- What about split-brain? No automatic protection (use network redundancy)