Pub/sub in Fork

  • Written by Tijs Verkoyen on Tuesday 12 July 2011
  • 4 comments

With the new release we introduce the initial version of the pub/sub-system. Publish/subscribe (pub/sub in short) is a pattern where sender (publishers) trigger an event, whereon receivers (subscribers) can subscribe. With this mechanism modules can be linked and are able to interact on certain events.

For instance, if you don't like the existing search module and like to implement Solr, this system could come in handy. You don't need to hack every module with some specific code. You can subscribe to events that are triggerd when a page is edited (after_edit), or when a blogpost is created (after_add), and execute the code to add/edit/delete the indexed data.

How does it work

There are multiple parts in the pub/sub-structure.

Trigger an event (Publish)

In this release we added a lot of events. If you write your own modules and want other modules to be able to subscribe to certain events, you can use the BackendModel::triggerEvent() or FrontendModel::triggerEvent()-method (depending on which application you are working on).

The methods have three arguments:

  • $module, the name of the module that triggers the event.
  • $eventName, the name of the event, this is up to you, but choose a logical name.
  • $data, optionally you can add data that will be send to all subscribers. For instance you can pass an array with all the data of the added item.

When an event is triggered, the system will check if there are subscribers. If there are no subscriptions, nothing will be done so no resources are wasted. If there are subscriptions, we will add a line in the queue for each subscription. When the items are inserted in the queue we will start processing the queue right away in the background.

Subscribe on an event

Ofcourse the events are useless when nothing subscribes to them. So, there is a method that can be used to subscribe to an event: BackendModel::subscribeToEvent() and FrontendModel::subscribeToEvent().

When you subscribe to an event, there are a few arguments that tell the system to which event you want to subscribe:

  • $eventModule, the name of the module that triggers the event.
  • $eventName, the name of the event whereon you want to subscribe.
  • $module, the name of the module that subscribes to the event.
  • $callback, the callback that will be executed when the event is triggered.

Besides a method to subscribe there is a method to unsubscribe from events also: BackendModel::unsubscribeFromEvent() and FrontendModel::unsubscribeFromEvent().

Queue

Each time an event is triggered we will check if the processing is ongoing, if not the processing is started. If the queue isn't empty one item will be locked and processed.

Processing means that we lock the item and execute the provided callback. If this was successfull the item will be removed from the queue, otherwise it will be marked as an error. When the first item is processed we will look in the queue if there are other items to process. If that isn't the case, the script is terminated so no resources are wasted.

Why in the background?

This is a tricky question, it was a lively discussion (some got hurt, nobody got killed). Each of the approaches had advantages and disadvantages. Because the queue is processed in the background we know for sure no code can interfere with the flow of the code that triggered the event. This roughly means that a badly functioning subscriber can not cause a perfectly valid subscriber to error. Next to that, it can slow down the original code. Because of the queue the events will be executed at some point in time, even when previous events have failed.

Feedback?

Because this is the initial version, we really want to hear your feedback on this topic. Tell us what is missing, tell us what you need to build the coolest module ever. If you have any questions, feel free to post them as a comment below.

Comments

Frederik wrote 12 years ago

Sweet, wil check it out.

Annelies wrote 12 years ago

@Tijs: I have a bit of a problem with the hooks when trying to send emails in the Frontend application:

"Use of undefined constant FRONTEND_LANGUAGE - assumed 'FRONTEND_LANGUAGE'"

Jeroen wrote 11 years ago

I'd like to see more information about the callback, is this an 'action', or f.e.: 'BackendBlogModel::deleteFromEvent'

Jeroen wrote 11 years ago

A valid $callback could be:

array('BackendBlogModel', 'delete)

So you place the following in an installer:

BackendModel::subscribeToEvent('location', 'after_delete', 'blog', array('BackendBlogModel', 'delete'));