The Chicago Boss API is mostly stable, but still might change before 1.0.

BossNews: Events for your data model

The BossNews API lets you cleanly separate notification logic from your models and controllers. You can specify model attributes and collections to watch, and have a callback function invoked when that part of the model changes. BossNews might be used to send email updates about changes occuring on a website, or it might be used in conjunction with BossMQ to provide users with real-time events (for example, to fire an alert when someone replies to a user's forum post).

The boss_news module

The boss_news module provides functions for creating and managing event listeners, called watches. Watches take a TopicString, which is a comma-separated list of topics to watch, and then execute the provided function when a topic changes. The following table summarizes valid topics and the events that the callback function will receive:

RecordId.Attributeupdated{Record, Attribute::atom(), OldValue, NewValue}
RecordId.*updated{Record, Attribute::atom(), OldValue, NewValue}
Type-*.Attributeupdated{Record, Attribute::atom(), OldValue, NewValue}
Type-*.*updated{Record, Attribute::atom(), OldValue, NewValue}

Examples of valid topics are:

The return value of the callback function can be used to cancel (or extend) the watch that invoked the function. This feature can be used to ensure that a callback is only performed once. Meaningful return values are:

(Other return values are ignored.)

Functions for managing watches are:

watch(TopicString::string(), CallBack) -> {ok, WatchId} | {error, Reason}

Watch records and attributes described by TopicString, and execute CallBack(Event, EventInfo) each time any of them changes. Note that the callback should be specified as a named fun and not a closure, or you may experience unexpected results during code reloads.

watch(TopicString::string(), CallBack, UserInfo) -> {ok, WatchId} | {error, Reason}

Same as watch/2, except that UserInfo will be passed as a third argument to the callback if the callback takes three arguments.

watch(TopicString::string(), CallBack, UserInfo, TTL) -> {ok, WatchId} | {error, Reason}

Same as watch/3, except that the watch expires after TTL seconds.

set_watch(WatchId, TopicString::string(), CallBack) -> ok | {error, Reason}

Create or replace a watch with WatchId.

set_watch(WatchId, TopicString::string(), CallBack, UserInfo) -> ok | {error, Reason}

Same as set_watch/3, except that UserInfo is passed to the callback.

set_watch(WatchId, TopicString::string(), CallBack, UserInfo, TTL) -> ok | {error, Reason}

Same as set_watch/4, except that the watch expires after TTL seconds.

cancel_watch(WatchId) -> ok | {error, Reason}

Cancel an existing watch identified by WatchId.

extend_watch(WatchId) -> ok | {error, Reason}

Extend an existing watch by the time-to-live specified at creation time.

The *_news.erl startup script

Listeners should be set up in the priv/init/<appname>_news.erl file in your project directory. The module should have one exported function, init/0, which is executed at server startup. This function is a convenient place to set up listeners before any web requests are received, but listeners can be set up anywhere in the application.

The script's init/0 function must return {ok, ListOfWatchIDs}. If the script is reloaded during the lifetime of the application (for example, via the admin application), then this list of watches will be cancelled before the script is executed again.

HTTP API for supporting other frameworks

If the admin application is installed, other applications can post data update notifications to a Chicago Boss server via a simple HTTP API:

    POST /admin/news_api/created/<record-id>
    POST /admin/news_api/updated/<record-id>
    POST /admin/news_api/deleted/<record-id>

The body of the POST request should include model attributes in the form new[<attr>]=<val> and old[<attr>]=<val>. The created API takes only "new" attributes. The deleted API takes only "old" attributes. The updated API takes both "new" attributes and their corresponding "old" attributes.

When invoked via the HTTP API, all values are passed to the listeners as strings.