CDI container and component lifecycle
After 0.0.8. The storage repair job,
RepairService, is on themasterbranch and not in release 0.0.8, where a node starts the peer-to-peer listener and the REST interface eagerly.
A Hedgehog node is a single program that runs several long-lived services at once: a peer-to-peer listener, a
local web interface, a record of the network’s parameters and a storage repair job. This page describes the
part that creates those services, starts them in the right order and shuts them down cleanly, so that one
daemon command is enough to bring a whole node to life.
Hedgehog is written in Java and delegates this work to a standard dependency-injection container (CDI, implemented by Weld). Each service is declared as a managed component, the container builds them and hands each one the others it needs, and nothing in the node wires itself together by hand. The wider picture is in the Architecture overview.
How a node starts
The hedgehog daemon command reads its options, starts the container and then simply waits. Everything that
matters happens while the container starts:
sequenceDiagram
autonumber
participant M as Hedgehog.main
participant PC as picocli
participant W as Weld container
participant EE as EagerExtension
participant S as P2PServer, RestServer,<br/>RepairService
M->>PC: execute(args)
PC->>PC: bind NetOptions / RestOptions
PC->>W: Daemon.run() starts the container
W->>W: discover components
W->>EE: ProcessBean for every component
EE->>EE: remember those marked @Eager
W->>EE: AfterDeploymentValidation
EE->>S: create now (@PostConstruct)
S->>S: bind P2P and REST ports,<br/>start topology thread and repair job
W->>W: install shutdown hook, fire ContainerInitialized
W-->>PC: container returned, main thread waits
The container creates components lazily, on first use, so a component that must be running from the start is
marked @Eager. A small extension, EagerExtension, finds those components once discovery is finished and
creates them before the container reports that it is ready. This is how the peer-to-peer server, the REST
server and the storage repair job are already running when startup completes.
Shared state and its guards
The list of known peers (Topology) and the map from open connections to peers (ChannelMap) are used by
many threads. Their methods carry @Protected and @Lock annotations, and ProtectedInterceptor turns those
into a read-write lock: any number of readers at once, or a single writer. There is one lock per component
instance, so the topology and the channel map do not block each other.
Some objects are not created by the container at all. Network handlers and scheduled tasks are built by the
networking library, and the REST resources by the web framework, so they look their dependencies up in the
container on demand (CDIUtil, CDIBridgeResource). The same pattern lets the REST layer reach the peer
network described in Peer-to-peer network protocol.
Some values are produced rather than declared. The application directory is created per use, and the spork database is shared by every user of it and loaded from disk on first use. Sporks are the signed network parameters described in Grid sporks; the container saves the database again when it shuts down.
How a node stops
POST /stop on the local REST interface, or the hedgehog cli stop command, wakes the
waiting main thread. The program exits, the container’s shutdown hook runs, and each component’s
@PreDestroy method closes its sockets and threads. The spork database is written to disk at that point.
Key facts
| Item | Value |
|---|---|
| Peer-to-peer listener | QUIC over UDP, default 0.0.0.0:52883 |
| REST interface | default localhost:52884 |
| Components started eagerly | P2PServer, RestServer, RepairService |
| Event-loop threads | 4 per server |
| QUIC data limit | 256 MiB per connection and stream |
| QUIC streams and idle timeout | 512 streams, 15 minutes |
hedgehog subcommands |
bootstrap, cli, daemon, util |
In tests
The test suite starts real containers instead of mocking components. Each test class gets its own container, and the server tests start 20 independent ones to check that nodes bind distinct ports. A test container does not start the eager components unless it asks for the extension, so tests start their servers explicitly. How the suite is built and run is covered in Build, testing and native image.
In the source
application/src/main/java/org/unigrid/hedgehog/Hedgehog.java- the entry point and its subcommands.application/src/main/java/org/unigrid/hedgehog/command/Daemon.java- thedaemoncommand.application/src/main/java/org/unigrid/hedgehog/model/cdi/CDIContext.java- starts the container and waits.application/src/main/java/org/unigrid/hedgehog/model/cdi/EagerExtension.java- eager component startup.application/src/main/java/org/unigrid/hedgehog/model/cdi/ProtectedInterceptor.java- the read-write guard.application/src/main/java/org/unigrid/hedgehog/server/p2p/P2PServer.java- the peer-to-peer listener.application/src/main/java/org/unigrid/hedgehog/server/rest/RestServer.java- the REST server.application/src/main/java/org/unigrid/hedgehog/model/producer/- producers for shared objects.