websocket-relay/.agents/summary/architecture.md
savinmax 905c241daa
Some checks failed
CI / test (push) Successful in 54s
CI / lint (push) Failing after 3m16s
Improve reliability, testing, and documentation
- Fix metrics: change MessagesTotal, ConnectionsTotal, DisconnectionsTotal
  from Gauge to Counter with proper _total naming convention
- Fix broadcast write-error handling: failed clients now get properly
  removed with accurate metrics updates
- Add graceful shutdown: SIGINT/SIGTERM handling with 10s timeout,
  CloseGoingAway frame sent to clients before disconnect
- Add integration tests: 11 tests using real WebSocket connections
  covering connect, broadcast, disconnect, concurrency, and shutdown
- Fix example client port: changed from 8000 to 8443 to match config
- Rewrite README.md to reflect current features and usage
- Add AGENTS.md and .agents/summary/ documentation for AI assistants
2026-06-11 19:14:19 +02:00

3.5 KiB

Architecture

System Architecture Overview

graph TB
    subgraph Clients
        C1[WebSocket Client 1]
        C2[WebSocket Client 2]
        C3[WebSocket Client N]
    end

    subgraph "WebSocket Relay Server"
        EP[HTTP/TLS Endpoint]
        HUB[Hub - Connection Manager]
        BC[Broadcast Channel]
        MET[Prometheus Metrics]
    end

    subgraph Monitoring
        PROM[Prometheus Scraper]
    end

    C1 -->|ws/wss| EP
    C2 -->|ws/wss| EP
    C3 -->|ws/wss| EP
    EP --> HUB
    HUB --> BC
    BC -->|relay to all| C1
    BC -->|relay to all| C2
    BC -->|relay to all| C3
    HUB --> MET
    MET -->|:9090/metrics| PROM

Design Pattern: Hub-and-Spoke

The application uses a Hub-and-Spoke (fan-out) pattern where:

  1. Hub is the central coordinator managing all WebSocket connections
  2. Spokes are individual WebSocket client connections
  3. Every message received from any client is broadcast to all connected clients
graph LR
    subgraph Hub
        REG[Register Channel]
        UNREG[Unregister Channel]
        BCAST[Broadcast Channel]
        CLIENTS[Client Map]
    end

    CONN[New Connection] --> REG
    REG --> CLIENTS
    DISC[Disconnection] --> UNREG
    UNREG --> CLIENTS
    MSG[Incoming Message] --> BCAST
    BCAST --> CLIENTS

Concurrency Model

The server uses Go's CSP (Communicating Sequential Processes) concurrency model:

sequenceDiagram
    participant Client
    participant Handler as HTTP Handler
    participant Hub as Hub.Run() goroutine
    participant Reader as ReadMessage goroutine

    Client->>Handler: HTTP Upgrade Request
    Handler->>Hub: register <- conn
    Hub->>Hub: Add to clients map
    Handler->>Reader: Start goroutine
    
    loop Read Messages
        Client->>Reader: WebSocket Frame
        Reader->>Hub: broadcast <- message
        Hub->>Hub: Iterate clients map
        Hub->>Client: WriteMessage (fan-out)
    end

    Reader->>Hub: unregister <- conn (on error/close)
    Hub->>Hub: Remove from clients map

Goroutine Lifecycle

Goroutine Purpose Lifetime
main HTTP server, accepts connections Application lifetime
Hub.Run() Processes register/unregister/broadcast channels Application lifetime
Per-client reader Reads messages from a single client Client connection lifetime
Metrics server Serves /metrics endpoint Application lifetime (if enabled)

Configuration Architecture

graph LR
    CLI[CLI Flag: --config-file] --> LOAD[config.Load]
    LOAD --> YAML[YAML Parser]
    YAML --> CFG[Config Struct]
    CFG --> SRV[Server Setup]
    CFG --> TLS[TLS Config]
    CFG --> MET[Metrics Setup]

Security Model

  • TLS Support: Optional TLS via cert/key PEM files
  • Origin Check: CheckOrigin allows all origins (permissive for relay use case)
  • No Authentication: The relay is designed as a transparent message forwarder
  • No Authorization: All connected clients can send/receive all messages

Deployment Architecture

graph TB
    subgraph "Build Pipeline"
        SRC[Source Code] --> CI[Gitea CI]
        CI --> TEST[go test]
        CI --> LINT[golangci-lint]
        TAG[Git Tag v*] --> REL[Release Pipeline]
        REL --> BIN_L[Linux amd64 Binary]
        REL --> BIN_M[macOS arm64 Binary]
    end

    subgraph "Runtime"
        BIN[Binary] --> CFG[config.yaml]
        CFG --> SERVER[WebSocket Server :8443]
        CFG --> METRICS[Metrics Server :9090]
    end