7.2 Service Internals

Under the hood, each service record has an associated fiber, a lightweight execution thread and shepherd as a whole follows the CSP (Concurrent Sequential Processes) model (see Introduction in Fibers). A service’s fiber encapsulates all the state of its corresponding service: its status (whether it’s running, stopped, etc.), its “running value” (such as the PID of its associated process), the time at which its status changed, and so on. Procedures that access the state of a service, such as service-status, or that modify it, such as start-service (see Interacting with Services), merely send a message to the service’s associated fiber.

This pattern follows the actor model: each of these per-service fibers is an actor6. There are several benefits:

There are other actors in the code, such as the service registry (see Service Registry). Fibers are used pervasively throughout the code to achieve concurrency.

Note that Fibers is set up such that the shepherd process has only one POSIX thread (this is mandated by POSIX for processes that call fork, with all its warts), and fibers are scheduled in a cooperative fashion. This means that it is possible to block the shepherd process for instance by running a long computation or by waiting on a socket that is not marked as SOCK_NONBLOCK. Be careful!

We think this programming model makes the code base not only more robust, but also very fun to work with—we hope you’ll enjoy it too!


Footnotes

(6)

There is one noteworthy difference compared to the actor model. In the “real” actor model, messaging among actors is asynchronous; in the CSP model, messaging is synchronous, which means that the sender and receiver must always rendezvous and their send/receive operation blocks until the other end is here to receive/send the message. See Context in Fibers, for more info.