* Add bump-changes * Add utility tests * Add utility tests * Bump to new version of esbuild and typescript * v0.7.3 * use platform rig 0.7.10 * upgrade: memory engine optimized; change name to (was recommended by Copilot and Onnikov, TODO: CHANGE CLIENT TOO!!!) Signed-off-by: Leonid Kaganov <lleo@lleo.me> * Fix rate limits bug * Bump versions * Fix lock file * Fix bug in queue cleanup * Add more tests for queue * Add api-test tests * Initial commit * Improve hierarchy + tests Add tests for hierarchy and few performance/memory optimizations. * Add more hierarchy tests * Move from Huly platform repository * Add docker tests setup * Fix test to be executed only once * Add connection tests * Fix package include source files * More tests * Create README.md * Fix pnpm lock * Fix packages publish * Remove broken tests * feat: adjust hulylake client for storage adapter Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Fix export * Fix publish * Fix message update (#114) Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com> * Bump version Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com> * Bump versions Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Fix lang store (#115) Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com> * update hulylake client Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Bump version Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Add hulylake storage adapter Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Bump version Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * fix validation issues Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * fix: do not fail on deseralization error and add logs Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * bump version -> 0.1.14 Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * fix collaboration test Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Update prettier and new update-deps script Prettier + svelte support * fix unstable ydoc tests Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Add tx ordering middleware * Fix ordering tests * Fix Kafka close of admin * Add tests for measurement and understand overhead * Fix not updated lock file * Fix update-deps * Fix update-deps * Use latest platform-rig * Fix deps * Add rush check to CI * Use latest versions * Bump versions * Fix lock file * validate json patch Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * bump version -> 0.1.15 Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * fix merge unit tests Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Script to sync eslint deps * Fix deps * Fix tests * Fix platform-rig detection * Update to latest platform-rig * Update to latest platform rig and core * Bump typescript * Bump typescript * Rollback eslint plugins * Fix lock file * Bump platform-rig * Update to latest platform-rig * update to latest platform-rig * Allow to compile svelte files * Add ui-test component for checking compile * Fix log levels rename compile ui -> compile ui-esbuild * Fix build * Bump esbuild svelte version * Chore: use fixed versions in update-deps Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com> * Chore: commit changes Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com> * Update deps * Add tests for session manager * Fix txOrdering implementation * Bump ordering * Prevent metrics zero values in measure + Fix format svelte files * Revert update-deps script logic * v0.7.19 * update to latest platform-rig * Update deps * Fix pnpm * Session counters * Fix pnpm lock * Add storage client Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Bump versions Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * fix versions Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Bump core * Fix pnpm * Get rid of communication dependency * Add copilot memory file * Use proper name for instructions file * Fix instructions * Use domain instead of test name in gauges * Update instructions file * fix front service upload Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * remove incorrect test Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Move packages to huly.core * Move packages to core, since they are not utils * Add global user profile Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com> * Fix lock file Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com> * Add support for memory limit check * Bump version * Fix pnpm * report more accurate upload progress Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * fic validation issues Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Fix deps Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com> * Move LowLevelStorage to server * Fix linting * Revert "Fix linting" This reverts commit54631d353e. * Revert "Move LowLevelStorage to server" This reverts commitaafb8f6f12. * feature: add regorus engine with permit file Signed-off-by: Leonid Kaganov <lleo@lleo.me> * Fix one second counters for memory usage * Fix kafka test * use fresh core * Version bump * fix: key parameter added Signed-off-by: Leonid Kaganov <lleo@lleo.me> * Fix readme and few author mistakes * Export domain schemas * Bump version * Tests (#117) Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com> * Bump version Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com> * feat: compact compact worker (#4) Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * bump version -> 0.1.16 Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Add TypeIdentifier Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Add change logs Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * rename send -> try_send Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Bump Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Fix pnpm lock Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Add identifier middleware, bump core Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Add subsciption methods to account client Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com> * Fix lock file Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com> * Fix reaction notification (#118) Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com> * Bump version Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com> * Improve find methods schemas to convert to valid types Signed-off-by: Nikolay Marchuk <nikolay.marchuk@hardcoreeng.com> * Add change description Signed-off-by: Nikolay Marchuk <nikolay.marchuk@hardcoreeng.com> * Do not transcode while recording Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Open telemetry support Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * use proper content type in multipart upload Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Bump versions Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * fix build (#26) Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Fix peers (#120) Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com> * Bump version Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com> * Add ActivityCollaborativeChange Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Update pnpm Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Allow to suspend errors on with * Fix pnpm cache * update versions * v0.7.17 for all * v0.7.11 * v0.7.14 * remove arc from worker Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * bump version -> 0.1.17 Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Rank for attributes Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Update pnpm Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Fix one second counters * Fix withContext and allow pass options * Fix formatting * Use updated deps * Bump versions * Update deps * Update deps to platform.core * add support for textColor mark Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * add support for textStyle mark Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Bump versions Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Bump versions again Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Fix Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Rework on second timers * fix merge of large blobs feched from s3 Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * bump version -> 0.1.18 Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * New subscription methods in account-client * Update lock file Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com> * Send error on find for wrong domain * Suspend connect custom errors events in traces * Bump client * Bump core * update deps * Fix lock file * Sorting for TypeIdentifier Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Bump version Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * add workspace usage info Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Bump versions Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> * Improve pg security perfomance Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Fix identifier middleware Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Update TxAccessLevel interface Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com> * Allow guest to update its identities Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com> * Add password login locked platform status Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com> * Fix Uptrace normalizeMarkdown errors Signed-off-by: Artem Savchenko <armisav@gmail.com> * Add change log Signed-off-by: Artem Savchenko <armisav@gmail.com> * Add txMatch to permission Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * update pnpm lock Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Bump Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Fix permission middleware Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Fix enum sorting Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Enable formatting check Signed-off-by: Andrey Sobolev <haiodo@gmail.com> * Enable formatting check * Add change Signed-off-by: Andrey Sobolev <haiodo@gmail.com> * Fix Uptrace NaN error Signed-off-by: Artem Savchenko <armisav@gmail.com> * feature: removed actors, improved performance Signed-off-by: Leonid Kaganov <lleo@lleo.me> * feature: ping from server to clients added Signed-off-by: Leonid Kaganov <lleo@lleo.me> * feature: ping from server to clients added Signed-off-by: Leonid Kaganov <lleo@lleo.me> * Compress kafka messages and fix exception in findAll Signed-off-by: Artem Savchenko <armisav@gmail.com> * Bump versions Signed-off-by: Artem Savchenko <armisav@gmail.com> * Bump versions Signed-off-by: Artem Savchenko <armisav@gmail.com> * Rush change Signed-off-by: Artem Savchenko <armisav@gmail.com> * Fix compression param Signed-off-by: Artem Savchenko <armisav@gmail.com> * Trigger change Signed-off-by: Artem Savchenko <armisav@gmail.com> * Clean up Signed-off-by: Artem Savchenko <armisav@gmail.com> * Trigger change Signed-off-by: Artem Savchenko <armisav@gmail.com> * Bump markdown version Signed-off-by: Artem Savchenko <armisav@gmail.com> * Enable sub projects * Fix wrong double symbol scripts * Include foundation packages * Add support for custom exclude filters Add support for custom exclude filters - by Andrey Sobolev - haiodo@gmail.com Signed-off-by: Andrey Sobolev <haiodo@gmail.com> * Bump Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Fix Uptrace filter is not a function error Signed-off-by: Artem Savchenko <armisav@gmail.com> * Sync versions Signed-off-by: Andrey Sobolev <haiodo@gmail.com> --------- Signed-off-by: Leonid Kaganov <lleo@lleo.me> Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com> Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com> Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com> Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> Signed-off-by: Nikolay Marchuk <nikolay.marchuk@hardcoreeng.com> Signed-off-by: Artem Savchenko <armisav@gmail.com> Signed-off-by: Andrey Sobolev <haiodo@gmail.com> Co-authored-by: Leonid Kaganov <lleo@lleo.me> Co-authored-by: Alexander Onnikov <Alexander.Onnikov@xored.com> Co-authored-by: Alexander Onnikov <Alexander.Onnikov@gmail.com> Co-authored-by: Kristina <kristin.fefelova@gmail.com> Co-authored-by: Alexey Zinoviev <alexey.zinoviev@xored.com> Co-authored-by: Denis Bykhov <bykhov.denis@gmail.com> Co-authored-by: Nikolay Marchuk <nikolay.marchuk@hardcoreeng.com> Co-authored-by: Alexander Onnikov <aonnikov@hardcoreeng.com> Co-authored-by: Artem Savchenko <armisav@gmail.com>
17 KiB
Core Concepts
Understanding the fundamental concepts of Huly Virtual Network is essential for building robust distributed systems.
Table of Contents
- Architecture Overview
- Network
- Agents
- Containers
- Clients
- Communication Patterns
- Lifecycle Management
- Endpoint References
- Container Kinds and Labels
Architecture Overview
Huly Network uses a hub-and-spoke architecture with three main components:
graph TB
subgraph "Network (Hub)"
N[Network Server]
R[Router]
REG[Container Registry]
end
subgraph "Agent 1"
A1[Agent]
C1A[Container A]
C1B[Container B]
end
subgraph "Agent 2"
A2[Agent]
C2A[Container C]
C2B[Container D]
end
subgraph "Clients"
CLIENT1[Client 1]
CLIENT2[Client 2]
end
CLIENT1 -->|Request Container| N
CLIENT2 -->|Request Container| N
N -->|Route to Agent| A1
N -->|Route to Agent| A2
A1 --> C1A
A1 --> C1B
A2 --> C2A
A2 --> C2B
Key Principles
- Centralized Coordination: The network server coordinates all agents and containers
- Distributed Execution: Containers run on agents, which can be distributed across multiple machines
- Dynamic Discovery: Clients discover and connect to containers through the network
- Automatic Lifecycle: The network manages container lifecycles based on client references
- Fault Tolerance: Automatic cleanup of failed agents and orphaned containers
Network
The Network is the central coordinator that:
- Maintains a registry of all agents and their capabilities
- Tracks all active containers and their locations
- Routes client requests to appropriate containers
- Manages container lifecycles (creation, reference counting, cleanup)
- Provides service discovery and load balancing
- Broadcasts events to clients about system changes
Network Responsibilities
interface Network {
// Agent management
register(record: AgentRecord, agent: NetworkAgentApi): Promise<ContainerUuid[]>
unregister(agentId: AgentUuid): Promise<void>
ping(agentId: AgentUuid): Promise<void>
// Container management
get(client: ClientUuid, kind: ContainerKind, options: GetOptions): Promise<[ContainerUuid, ContainerEndpointRef]>
release(client: ClientUuid, uuid: ContainerUuid): Promise<void>
list(kind?: ContainerKind): Promise<ContainerRecord[]>
// Communication
request(target: ContainerUuid, operation: string, data?: any): Promise<any>
// Discovery
agents(): AgentRecord[]
kinds(): ContainerKind[]
}
Network Server
The network server listens on a TCP port (default: 3737) and:
- Accepts connections from clients and agents
- Uses ZeroMQ for high-performance messaging
- Handles concurrent requests efficiently
- Maintains connection health through ping/pong
Example: Starting a Network Server
import { NetworkImpl, TickManagerImpl } from '@hcengineering/network-core'
import { NetworkServer } from '@hcengineering/network-server'
const tickManager = new TickManagerImpl(1000) // 1000 ticks/sec
tickManager.start()
const network = new NetworkImpl(tickManager)
const server = new NetworkServer(
network,
tickManager,
'*', // Bind to all interfaces
3737 // Port
)
console.log('Network server running on port 3737')
Agents
Agents are worker processes that:
- Host and manage containers
- Register with the network to advertise capabilities
- Create containers on-demand or pre-provision them (stateless)
- Handle container lifecycle (start, stop, health checks)
- Route requests between clients and containers
Agent Capabilities
Each agent declares which container kinds it can create:
// Note: For production code, use serveAgent() on the client
// This example uses AgentImpl directly for educational purposes
const agent = new AgentImpl('my-agent' as AgentUuid, {
session: async (options) => {
/* create session container */
},
workspace: async (options) => {
/* create workspace container */
},
query: async (options) => {
/* create query container */
}
})
Agent Registration
Agents register with the network to announce availability:
import { NetworkAgentServer } from '@hcengineering/network-client'
const agentServer = new NetworkAgentServer(
tickManager,
'localhost', // Network host
'*', // Bind address
3738 // Agent port for container connections
)
await agentServer.start(agent)
// Register with network
await client.register(agent)
Agent Health
Agents must:
- Send regular pings to the network (default: every 1 second)
- Respond to health checks
- Handle graceful shutdown
- Clean up containers on termination
If an agent fails to ping within the aliveTimeout (default: 3 seconds), the network:
- Marks the agent as dead
- Removes all its containers
- Broadcasts removal events
- Allows standby agents to take over (for stateless containers)
Containers
Containers are the workhorses of the system. They:
- Implement specific business logic
- Process requests from clients
- Maintain internal state
- Broadcast events to connected clients
- Are automatically created and destroyed based on demand
Container Interface
Every container must implement:
interface Container {
// Handle incoming requests
request(operation: string, data?: any, clientId?: ClientUuid): Promise<any>
// Health check
ping(): Promise<void>
// Cleanup and shutdown
terminate(): Promise<void>
// Event broadcasting support
connect(clientId: ClientUuid, broadcast: (data: any) => Promise<void>): void
disconnect(clientId: ClientUuid): void
// Optional termination callback
onTerminated?(): void
}
Container Lifecycle
stateDiagram-v2
[*] --> Creating: Client requests container
Creating --> Active: Factory creates instance
Active --> Referenced: Client holds reference
Referenced --> Active: Client releases reference
Active --> Terminating: Timeout expires (no references)
Referenced --> Terminating: All clients released
Terminating --> [*]: Cleanup complete
Key lifecycle events:
- Creation: Factory method called when container is requested
- Active: Container is running and processing requests
- Referenced: At least one client holds a reference
- Idle Timeout: Container kept alive for
containerTimeoutafter last reference released - Termination:
terminate()called, then removed from network
Container Types
Stateful Containers (Dynamic)
Created on-demand when requested:
// Note: For production code, use serveAgent() on the client
// This example uses AgentImpl directly for educational purposes
const agent = new AgentImpl('agent-1' as any, {
'user-session': async (options: GetOptions) => {
const uuid = options.uuid ?? generateUuid()
const container = new UserSessionContainer(uuid, options)
return {
uuid,
container,
endpoint: `session://agent1/${uuid}` as any
}
}
})
Stateless Containers (Pre-provisioned)
Pre-created for high availability:
const leaderContainer = new LeaderContainer('leader-001' as ContainerUuid)
agent.addStatelessContainer(
'leader-001' as ContainerUuid,
'leader' as ContainerKind,
'leader://agent1/leader-001' as ContainerEndpointRef,
leaderContainer
)
Multiple agents can register the same stateless container UUID. The network accepts the first and rejects others, enabling automatic failover.
Container Example
import type { Container, ContainerUuid, ClientUuid } from '@hcengineering/network-core'
class DataStoreContainer implements Container {
private data = new Map<string, any>()
private connections = new Map<ClientUuid, (data: any) => Promise<void>>()
constructor(readonly uuid: ContainerUuid) {}
async request(operation: string, data?: any): Promise<any> {
switch (operation) {
case 'set':
this.data.set(data.key, data.value)
await this.broadcast({ type: 'dataChanged', key: data.key })
return { success: true }
case 'get':
return { value: this.data.get(data.key) }
default:
return { error: 'Unknown operation' }
}
}
async ping(): Promise<void> {}
async terminate(): Promise<void> {
this.data.clear()
this.connections.clear()
}
connect(clientId: ClientUuid, broadcast: (data: any) => Promise<void>): void {
this.connections.set(clientId, broadcast)
}
disconnect(clientId: ClientUuid): void {
this.connections.delete(clientId)
}
private async broadcast(event: any): Promise<void> {
const promises = Array.from(this.connections.values()).map((fn) => fn(event))
await Promise.all(promises)
}
}
Clients
Clients are applications or services that:
- Connect to the network server
- Request containers by kind and optional criteria
- Send requests to containers
- Receive events from containers
- Manage container references (acquire/release)
Client Connection
import { createNetworkClient } from '@hcengineering/network-client'
const client = createNetworkClient(
'localhost:3737', // Network address
3600 // Alive timeout in seconds (optional)
)
await client.waitConnection(5000) // Wait up to 5 seconds
Requesting Containers
Clients request containers by kind and optional criteria:
// Get any container of this kind
const ref = await client.get('user-session' as ContainerKind, {})
// Get specific container by UUID
const ref = await client.get('user-session' as ContainerKind, {
uuid: 'session-123' as ContainerUuid
})
// Get container with labels
const ref = await client.get('workspace' as ContainerKind, {
labels: ['premium', 'us-west']
})
// Get container with extra data
const ref = await client.get('query-engine' as ContainerKind, {
extra: { database: 'analytics', userId: 'user-456' }
})
Client API
interface NetworkClient {
// Container management
get(kind: ContainerKind, request: GetOptions): Promise<ContainerReference>
list(kind?: ContainerKind): Promise<ContainerRecord[]>
// Agent management
register(agent: NetworkAgent): Promise<void>
unregister(agentId: AgentUuid): Promise<void>
// Discovery
agents(): AgentRecord[]
kinds(): ContainerKind[]
// Events
onUpdate(listener: NetworkUpdateListener): () => void
// Connection
close(): Promise<void>
}
Communication Patterns
Huly Network supports multiple communication patterns:
1. Request/Response (Synchronous)
Direct request to container with response:
const result = await containerRef.request('processData', {
value: 42
})
console.log(result) // { processed: true, result: 84 }
2. Fire-and-Forget (Asynchronous)
Send data without waiting for response:
await containerRef.request('logEvent', {
event: 'user_login',
timestamp: Date.now()
})
3. Event Broadcasting (Publish/Subscribe)
Container broadcasts events to all connected clients:
// Client side
const connection = await containerRef.connect()
connection.on = async (event) => {
console.log('Received:', event)
}
// Container side
connect(clientId: ClientUuid, broadcast: (data: any) => Promise<void>): void {
this.clients.set(clientId, broadcast)
}
// Broadcast to all clients
for (const broadcast of this.clients.values()) {
await broadcast({ type: 'update', data: changes })
}
4. Bidirectional Streaming
Establish persistent connection for streaming:
const connection = await containerRef.connect()
// Receive stream
connection.on = async (chunk) => {
console.log('Chunk:', chunk)
}
// Send requests
await connection.request('subscribe', { topic: 'updates' })
await connection.request('getData', { range: [0, 100] })
Lifecycle Management
Reference Counting
The network uses reference counting to manage container lifecycles:
- Each
client.get()increments the reference count - Each
containerRef.close()decrements it - Containers with zero references are kept alive for
containerTimeout - After timeout, containers are automatically terminated
// Acquire reference (ref count = 1)
const ref1 = await client.get('service' as any, { uuid: 'svc-1' })
// Acquire another reference to same container (ref count = 2)
const ref2 = await client.get('service' as any, { uuid: 'svc-1' })
// Release first reference (ref count = 1)
await ref1.close()
// Release second reference (ref count = 0)
await ref2.close()
// Container kept alive for containerTimeout, then terminated
Health Monitoring
The network continuously monitors health:
Agent Health:
- Agents must ping every
pingInterval(default: 1 second) - Network marks agent as dead after
aliveTimeout(default: 3 seconds) - Dead agents' containers are removed
Container Health:
- Containers respond to
ping()calls - Failed pings may trigger termination
- Unhealthy containers are removed from registry
Graceful Shutdown
Proper cleanup on shutdown:
// Container cleanup
async terminate(): Promise<void> {
// 1. Notify connected clients
await this.broadcastShutdown()
// 2. Close external connections
await this.database.close()
// 3. Clear internal state
this.data.clear()
// 4. Release resources
this.connections.clear()
}
// Agent cleanup
await agentServer.close()
tickManager.stop()
// Client cleanup
await containerRef.close()
await client.close()
// Server cleanup
await server.close()
tickManager.stop()
Endpoint References
Containers are addressed by endpoint references:
type ContainerEndpointRef = string & { _containerEndpointRef: true }
Endpoint Types
-
Direct Endpoint: Direct connection to container
tcp://host:port/uuid -
Routed Endpoint: Connection through agent
agent://host:port:agentId/uuid -
No-Connect Endpoint: Request-only, no persistent connection
noconnect://host:port/uuid
Parsing Endpoints
import { parseEndpointRef, EndpointKind } from '@hcengineering/network-core'
const parsed = parseEndpointRef(endpoint)
console.log(parsed.kind) // EndpointKind.direct | routed | noconnect
console.log(parsed.host) // Host address
console.log(parsed.port) // Port number
console.log(parsed.uuid) // Container UUID
console.log(parsed.agentId) // Agent ID (for routed)
Container Kinds and Labels
Container Kinds
Containers are categorized by kind (string type):
type ContainerKind = string & { _containerKind: true }
Examples:
'user-session'- User session management'workspace'- Workspace containers'query-engine'- Query processing'transactor'- Transaction handling
Agents declare which kinds they support:
// Note: For production code, use serveAgent() on the client
// This example uses AgentImpl directly for educational purposes
const agent = new AgentImpl('agent-1' as any, {
'user-session': sessionFactory,
workspace: workspaceFactory,
'query-engine': queryFactory
})
Labels
Containers can have labels for fine-grained selection:
// Create container with labels
await client.get('workspace' as any, {
labels: ['premium', 'us-west', 'production']
})
// Labels enable:
// - Multi-tenancy (tenant ID as label)
// - Geographic routing (region labels)
// - Tier-based selection (free, premium, enterprise)
// - Environment separation (dev, staging, production)
Get Options
interface GetOptions {
uuid?: ContainerUuid // Specific container UUID
extra?: Record<string, any> // Additional parameters for factory
labels?: string[] // Labels for selection
}
Summary
Key concepts to remember:
- Network = Central coordinator
- Agent = Worker node hosting containers
- Container = Service instance with business logic
- Client = Application requesting containers
- Reference Counting = Automatic lifecycle management
- Endpoint = Address for reaching a container
- Kind = Container type/category
- Labels = Fine-grained selection criteria
These concepts form the foundation for building scalable, fault-tolerant distributed systems with Huly Network.
Next Steps
- Container Development Guide - Build your first container
- Agent Development Guide - Create custom agents
- Client Usage Guide - Connect and use containers
- Production Deployment - Deploy to production
Need more help? Check the Troubleshooting Guide or Examples.