In last week’s post I talked about how Events can be treated like Signals, this week we’ll be looking at how Events can be treated like Methods. That might seem a little surprising, since normally one considers signals and methods as very different things, but to Upstart they are both just events.
What do I mean by Methods? You’ve almost certainly done some kind of programming, even if just a little scripting, so you should know about methods or functions.
In contrast to signals, which are just a notification that something happened on the system, a method is a request for the system to do something on your behalf. Usually to make some kind of change to the system state.
Likewise in contrast to the signals where you don’t care about the result, for a method you want to wait for the changes to be completed and perhaps even be notified if the method failed.
It’s just as easy to implement a method in Upstart as it is to implement something that considers an event a signal. Here’s an example of how you might implement a suspend method:
start on suspend task exec pm suspend
Doesn’t look that much difference from a signal, the only new stanza in this is task (and that’s not necessary for a method either). So what happens if we want to trigger a suspend? We use the command:
root@worldofwarcraft:~# initctl emit suspend
The difference here from emitting a signal we demonstrated in the previous post is that we aren’t using the –no-wait flag.
So we emit the suspend event, and Upstart will start our job as a result; but initctl emit will not return immediately, it waits for the results of the event to complete before it returns.
Because we used the task stanza in the configuration, we’ve told Upstart that the process we execute is expected to take a limited amount of time and then finish by itself. This means that Upstart will not believe the job is complete until the process has exited, and will continue to block the event while it is still running.
Finally if the command exited with an error, that error is propagated back to the event that started it, and the initctl emit command will exit with an error code.
So now we can use Upstart events and jobs for two different purposes; we can announce changes to the system, and we can use them as methods to make changes to the system.
The most typical event that is used as a methods on your system is the runlevel event used to change the runlevel for System-V compatibility and generally emitted by the telinit and shutdown tools. The /etc/init/rc.conf script that handles it can be pretty simple and looks not unlike the suspend example above:
start on runlevel [0123456] task exec /etc/init.d/rc $RUNLEVEL
What happens if you don’t include task? Well, that means Upstart will consider the job as ready when the process executed is running, and the event will be unblocked and initctl emit will return. If the service fails to start, then initctl will return with an error. This is great for methods that start (or stop) services.
Side-note: the start and stop commands act very much like method events, they block until the service is running or the task has finished and they return errors as well. However they’re not actually implemented as events right now, an oversight I intend to correct in Upstart 2.
(reposted from http://upstart.at/2010/12/16/events-are-like-methods/ – post comments there)