1 Internals
Félix Saparelli edited this page 2023-05-07 11:22:58 +12:00

The lifecycle of watchexec goes like this:

paint

So, events sourced from the file system, processes launched by watchexec, stdin, signals, and events manually sent in via Watchexec::send_event() all go into a channel. (That channel is actually also a priority queue, so that more urgent events like Ctrl-C can bypass a congested event queue, for example.)

That channel is consumed by the action worker. The action worker starts by the "throttle + filter" step, which is a big loop that builds up a Vec of Events that pass filters within the "throttle duration". Once it's "out of throttle", ie it's reached the end of the throttle duration and it has at least one event that's passed the filters, it makes an Action which essentially wraps that Vec<Event>.

Then the action handler is called, with this Action as argument. The handler can do anything (but should return quickly to avoid holding up Watchexec) but the main thing it does is it sets the Outcome of the Action. That's an intentionally restrained way to give commands to Watchexec's internal process manager, which is called Supervisor.

paint

What the supervisor does is it starts a process (technically it can supervise a sequence of processes but let's keep things simple), and then holds a reference to it. When an action returns an Outcome, that may translate to a command to send to the Supervisor, like "send the process a signal" or "kill the process" or "wait for it to stop" or "start a new process" (which can only happen if the supervisor is idle aka doesn't have a running process at the moment). At the same time, the supervisor will also send an event down the events channel when the process quits, which are then handled in the exact same way by the whole machinery above.

paint

When the supervisor is about to start a process, it will prepare it then call the pre_spawn handler, which can be used to modify the process call a bit or to send a notification out or print a message or something. After that returns, the supervisor starts the process, and then it calls the post_spawn handler. That one's less useful but has the new process's PID for example.

All these things are exposed, and if some things aren't I'm likely to accept PRs to expose them in the public API (unless I strongly feel they shouldn't be).

(If you have graphics chops and can remake those awful mouse-drawn diagrams a little better, help appreciated!)