Skip to content

Network Management

Data acquisition (DAQ) and processing systems are, most of the time, distributed systems: several independent programs need to exchange data over a network, reliably and continuously. Phoenix2 addresses this at two levels:

  • PhoenixSocket provides a generic socket abstraction, so that application code can send and receive data without being tied to a specific network technology.
  • PhoenixSwarm builds on top of it to turn a regular program into an autonomous daemon, able to exchange typed data with other daemons in a distributed deployment (Kubernetes, Slurm, HTCondor, ...).

PhoenixSocket

PhoenixSocket is the low-level communication library used throughout Phoenix2. Its goal is to decouple application code from the underlying transport technology, so that the way data is exchanged can evolve (or be replaced) without ever touching the code that uses it.

One API, several backends

Instead of using a networking library directly, application code talks to a single generic socket API (send, recv, isConnected, ...). Behind that API, a backend is responsible for actually moving the bytes. PhoenixSocket currently ships with:

  • a ZeroMQ backend, for real network / inter-process communication. This is the default, production-grade backend.
  • a Unix domain socket backend, for lightweight local inter-process communication on the same machine.
  • a mock backend, which does not use the network at all: it reads and writes data to a file instead. See the Mock testing page for a full explanation of why and how this is used.
flowchart LR
    App["Application code"] --> GS["Generic Socket API"]
    GS --> ZMQ["ZeroMQ backend"]
    GS --> Unix["Unix socket backend"]
    GS --> Mock["Mock backend"]

Because every backend implements the exact same API, switching from one to another is a configuration choice, not a rewrite. This is what makes it possible, for instance, to develop and test a whole pipeline using the mock backend on a laptop, then run the very same code against the real ZeroMQ backend once deployed.

Advantages

  • Maintainability: replacing a communication technology (upgrading ZeroMQ, or introducing a new backend) only requires implementing the backend contract; application code is unaffected.
  • Testability: the mock backend allows unit and integration tests to run without any real network, in a single process, in milliseconds.
  • Consistency: PhoenixSocket is available in C++, Rust and Python, sharing the same wire format, so components written in different languages can talk to each other transparently.

PhoenixSwarm

PhoenixSwarm builds on top of PhoenixSocket to solve a different problem: how to turn a normal program into a daemon that can take part in a distributed system, without having to hand-write connection management, message routing, or monitoring every time.

From a program to a daemon

A swarm is a collection of daemons, each one an independent process with its own address and port, exchanging typed messages with the other members of the swarm. Rather than having each daemon poll for data, PhoenixSwarm follows a push model: every daemon actively sends its data to the daemons that need it.

Each daemon owns a single receiver socket. When a message arrives, an internal dispatcher looks at the type of the data and automatically routes it to the function or class responsible for handling that type. As a developer, this means you write one handler per data type, and PhoenixSwarm takes care of calling it whenever the corresponding message shows up.

flowchart LR
    D1["Daemon A"] -->|typed message| D2["Daemon B receiver socket"]
    D2 --> Dispatch["Dispatcher"]
    Dispatch -->|type 1| H1["Handler 1"]
    Dispatch -->|type 2| H2["Handler 2"]
    Dispatch -->|type 3| H3["Handler 3"]

Mockable by design

Since PhoenixSwarm communicates through PhoenixSocket, it inherits the same real / mock duality described in Mock testing. A swarm can run in:

  • Normal mode, using the real backend in production,
  • Mock mode, replaying previously recorded data with no network involved, ideal for tests,
  • Record mode, using the real backend while simultaneously capturing every exchanged message for later replay.

Statistics, out of the box

Every daemon automatically collects statistics on the data it processes (event counts, min/max/average values, rates, latency), and periodically reports them to a central statistics manager. This gives visibility into a distributed swarm without any extra code from the developer.

Configuring a swarm

A whole swarm topology, addresses, ports, timeouts, communication settings, and statistics options, is described in a single configuration file (TOML, YAML, or JSON). This keeps the deployment of a distributed pipeline declarative and easy to reproduce, whether it runs on a laptop, in Kubernetes, on Slurm, or on HTCondor.

Advantages

  • Simplicity: turns any program into a distributed daemon with minimal boilerplate, one handler function per data type.
  • Portability: the same swarm can be deployed on very different infrastructures (Kubernetes, Slurm, HTCondor, ...) by only changing its configuration file.
  • Observability: built-in statistics collection makes it easy to monitor a distributed pipeline in production.
  • Testability: fully inherits PhoenixSocket's mock/record mechanism, so entire distributed pipelines can be tested offline.