Signals

Signals in Moya are a way for your project code to respond to various events that may occur during the processing of a request, or at other points during the lifetime of the server. For example, you may want to run some code when server starts up, or when an object is written to the database.

Writing Handlers

Signals are identified by a string in dotted notation. For example, sys.startup, is a signal for the server starting up. You may write code that handles a signal with the <handle> tag. Here's an example of handling the sys.startup signal:

<handle signal="sys.startup">
    <echo>Moya is starting up. To infinity, and beyond!</echo>
</handle>

If you add the above code to your project (it can go anywhere), Moya will display text in the console when you run the server. Naturally, in a real project a signal handler would so something more useful.

The signal attribute of <handle> may also accept wildcards – an asterisk is used to indicate that it will match anything with the same prefix. For example, if you were to set signal to sys.*, the handler would be invoked for any signal in the sys namespace.

Senders

Some signals have an associated sender, which is the library name of an element from which the signal is sent. For example, database related signals set the sender to the model name. You can whose to handle signals from a given sender with the sender attribute of <handle>. For example, the following handler will be invoked for every database signal sent from the User model:

<handle signal="db.*" sender="moya.auth#User">
    <echo>DB signal handled</echo>
</handle>

Signal Object

When a handler is invoked, Moya passes in a signal object with information regarding the signal. It contains three keys; name is the name of the signal, sender is the sender, and data is a dictionary containing extra information regarding the signal.

The contents of a signal's data dictionary vary according to the signal. For example, database related signals contain a value called object, which is the database object associated with the signal. Here's an example of a signal handler used in the Auth library:

<handle signal="db.before-update" from="moya.auth#User">
    <!-- Hash password automatically -->
    <let user="signal.data.object" />
    <call macro="#hashpassword" if="'$' not in user.password"
        dst="user.password" let:password="user.password"/>
</handle>

This handler is invoked just prior to writing a User object to the database. The handler hashes the password, so as not to store it in plain text. If we didn't use a handler here, we would have to cut and paste a line of code to every point where the User model is saves – which would be prone to errors.

Custom Signals

Some signals are sent by Moya itself, but you may also write code that sends, or fires custom signals. This allows you to respond to events without cluttering up your code. The <fire> tag is used to fire a custom signal. You can set the name of the signal to fire with the signal attribute, and the sender with the sender attribute. Additional data (which will be stored in signal.data) is set via the moya-codelet map. Here's an firing a signal:

<fire signal="moyaproject.sushifinder.out-of-stock" let:item="Tuna Roll" />

The following would catch the above signal:

<handle signal="moyaproject.sushifinder.out-of-stock">
    <echo>We need to order more ${signal.data.item}s!</echo>
</handle>

Naming Convention

Signal names with a single dot, such as db.before-update, sys.startup, are reserved by Moya. Custom signals should be named with the prefix of the library they are being sent from, e.g. moyaproject.sushifinder.out-of-stock.

If signals fall in to broad catagories, it is a good idea to name your signals to reflect that. For example, you could have moyaproject.sushifinder.stock.out-of-stock and moyaproject.sushifinder.stock.low-stock etc. A single handler may be written to respond to all stock related signals (with a signal attribute of moyaproject.sushihandler.stock.*).

Debugging

Moya intentionally ignores all exceptions that occur within signal handlers. Otherwise, you could never be sure that code you write won't break due to a bug in a signal handler (possibly written by a third party).

If a traceback does happen within a signal handler, Moya will write a message to the logs. Moya will also display a trace in the console if debug mode is enabled. You can also step through code in signal handlers and insert <breakpoint> tags as normal.

If you enable log_signals in Project Settings, Moya will write a message to the log every time it sends a signal. You could also replicate this with a catch all signal handler, such as the following:

<handler signal="*">
    <echo>Signal ${signal.name} detected</echo>
    <echo>Sent by ${signal.sender or 'nobody'}</echo>
    <echo>Signal data:</echo>
    <echo obj="signal.data"/>
</handler>

Built-in Signals

The following signals are built-in to Moya.

System

System signals are sent at various points in the life-time of the server. System signals begin with the prefix sys.

sys.startup
Sent when the server is starting up.

Request

A number of signals are sent at several points during the request process. Request signals begin with the request prefix.

request.pre-dispatch
This signal is sent immediately prior to processing a request. Signal data contains no values.
request.post-dispatch
This signal is sent immediately after processing a request, but before the result of that request (which may be content or another renderable) has been rendered in to html. The result is stored in the signal data, as result.
request.response
This signal is sent once a valid response object has been created. It is this response which will be ultimately sent to the user. The response object is stored in the signal data as response.
request.end
This signal is send at the very end of the request process, after the response has been sent. The signal data contains the response object.Note, that since the response has been sent when the request.end signal is fired, modifying the response will have no effect.