Files
+1 98652c6476 Include sub projects (#10201)
* 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 commit 54631d353e.

* Revert "Move LowLevelStorage to server"

This reverts commit aafb8f6f12.

* 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>
2025-11-26 19:15:30 +05:00

17 KiB

Core Concepts

Understanding the fundamental concepts of Huly Virtual Network is essential for building robust distributed systems.

Table of Contents

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

  1. Centralized Coordination: The network server coordinates all agents and containers
  2. Distributed Execution: Containers run on agents, which can be distributed across multiple machines
  3. Dynamic Discovery: Clients discover and connect to containers through the network
  4. Automatic Lifecycle: The network manages container lifecycles based on client references
  5. 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:

  1. Marks the agent as dead
  2. Removes all its containers
  3. Broadcasts removal events
  4. 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:

  1. Creation: Factory method called when container is requested
  2. Active: Container is running and processing requests
  3. Referenced: At least one client holds a reference
  4. Idle Timeout: Container kept alive for containerTimeout after last reference released
  5. 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

  1. Direct Endpoint: Direct connection to container

    tcp://host:port/uuid
    
  2. Routed Endpoint: Connection through agent

    agent://host:port:agentId/uuid
    
  3. 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:

  1. Network = Central coordinator
  2. Agent = Worker node hosting containers
  3. Container = Service instance with business logic
  4. Client = Application requesting containers
  5. Reference Counting = Automatic lifecycle management
  6. Endpoint = Address for reaching a container
  7. Kind = Container type/category
  8. Labels = Fine-grained selection criteria

These concepts form the foundation for building scalable, fault-tolerant distributed systems with Huly Network.

Next Steps


Need more help? Check the Troubleshooting Guide or Examples.