User Tools

Site Tools


Action/Trigger (Notifications)

Author: Bill Erickson
Created on: Dec. 7, 2009

Important Concepts & Terminology


See the description in Dan Scott's Evergreen Workshop


A reference to an action within the ILS. This is how we indicate what types of behaviour we want to react to. Examples include "hold.available" (item became ready for pickup from the holds shelf) and "checkout.due" (circulating item is due).

  • Hooks have a core object type which defines the primary context object for the action. The core type is represented by the IDL class name. For example, the core type for "checkout.due" is "circ", the core type for "hold.available" is "ahr".
  • Hooks can be active or passive. An active hook is one whose event creation occurs in real time. An example of an active hook is "hold.available". It is considered "active", because an action occurs within the ILS from which to fire off the event creation. In other words, a copy was physically scanned in and put on the shelf. Events for passive hooks are created in batch via regularly scheduled (CRON) processes. An example of a passive hook would be "checkout.due". There is no action within the ILS that occurs the moment an item becomes due. It's simply the result of passing time.

Module that validates context data prior to reaction. This is critical for supporting delayed reactions. Common examples include "HoldIsAvailable", "CircIsOverdue", and "CircIsOpen".

For developers: The system looks for validator modules in the OpenILS::Application::Trigger::Validator namespace. If they are not found, it searches the Perl library path


Module that defines how the system should respond to actions that match configured hooks. The most common example is "SendEmail".

For developers: The system looks for reactor modules in the OpenILS::Application::Trigger::Reactor namespace. If they are not found, it searches the Perl library path.


Module that performs post-reaction cleanup operations. The system support success cleanups and failure cleanup modules. This type of module is useful for cleaning up temporary files, etc.

Event Definitions

The Event Definition is the heart of the action/trigger configuration. It ties together a hook, validator, reactor, cleanup(er), template, and other settings to define a single reaction context. If you said, "I want to set up 7-day overdue email notices", you'd be talking about configuring an event definition.

Under normal circumstances, the hooks, validators, reactors, and cleanup modules will already be in place. All an administrator needs to do is set up the event definition to pull those pieces together. Below is a discussion of the event definition fields and how they are used.

Event Definition Fields

Owning Library

The context library for the event definition. This can be any organization unit in the hierarchy. This value is important because it defines the scope of the event definition. If the Owning Library has descendant org units (e.g. a consortium or a system), actions that occur at all descendant org units are relevant to the event definition. If the owning library is a single branch, then only actions at that branch are relevant. This gives admins the flexibility to define, for example, a single 7-day overdue notice for an entire consortium, or one per system, branch, etc.


Human-friendly name for an event definition. This can be anything as long as it is unique to the owning library. A good rule of thumb for naming an event definition is to summarize the hook, reactor, and delay. For example, "7-Day Courtesy Email Notice".


A reference to the hook (described above)


Event definitions can be turned off by setting the active flag to false.

Processing Delay

This value defines the amount of time the system should wait after a target object becomes "relevant" before reacting on that target object. This value is stored in the database as an interval data-type, use compatible input formats. Some examples will help here:

  • Overdue notices use the "checkout.due" hook. An item is technically due the second the due date hits. It is at that point the circulation becomes relevant in the context of the checkout.due hook. The goal for this type of notice, though, is to react 7 days after the item becomes relevant, i.e. 7 days past due (aka overdue). Note, for interval fields, you can use English text like "7 days", "3 months", etc.
  • Courtesy notices also use the "checkout.due" hook. In this context, though, we take advantage of looking into the future, which is something that can only be done when using passive hooks. Remember, passive hook event creation occurs as the result of batch processes and not from something happening within the ILS. The fact that, technically, the item won't yet be relevant in the context of the checkout.due hook is OK. In fact, the item may never relevant, because it may be checked in before it becomes due. We don't care. (Nerd aside: It's the Schrodinger's cat of event definitions. It may become relevant, but we'll never know, because we're not going to look.) All we care about is when it theoretically would become relevant. In this case, you would use a negative delay to signify the notification should be delivered exactly X days before the target becomes relevant in the context of the hook. In the delay field, you would enter a value like "-3 days".
  • Hold available notification using the hold.available hook. The hold is available (thus, relevant) the moment it is scanned in at the pickup library. You may want to delay the notice by an hour to make sure the copy is in good condition, etc.
Processing Delay Context Field

This is the field on the target object that defines the time stamp to use as the base time for calculating the time since the target became relevant or, in the case of looking into the future, the time until the target becomes relevant. This value is used to determine if a given target falls within the configured processing delay.

For checkout.due, the delay context field is the due date. With a 7-day notice, we add 7 days to the due_date to determine if the item is in fact 7 days overdue. For hold.available, the delay field is shelf_time. With a 1-hour delay, the system just adds 1 hour to the shelf_time value to determine if the system has waited long enough before sending the notice.

The field name maps to a <field> entry in the IDL for the target object's class. The field must be a date/time field.

Processing Group Context Field

This field is used to group events so they can be reacted upon en masse. The most common example of this is to group by the user field on the target object so that a patron, for example, will only receive 1 email for all items that are 7 days overdue and not 1 per item.

The field name maps to a <field> entry in the IDL for the target object's class.


The validator module to use. To create a custom validator add code/modules to the OpenILS::Application::Trigger::Validator package and create an entry for this new code in the list of Validators.


The reactor module to use.

Failure Cleanup

The failure cleanup module to use (optional)

Success Cleanup

The success cleanup module to use (optional)


A string used to distinguish among events that should be run (by the script) at different times.

If a site is busy or large enough that all the events typically run overnight won't be able to finish by morning if they're all run in a big lump, or if you have some events that you don't even need to run every night, you can use the granularity field (and the –granularity and –granularity-only options of to group events and selectively run them.

Max Event Validity Delay
Opt-In Setting Type
Opt-In User Field

A template toolkit input document, data are specified using the Event Environment and Event Parameters options for the event definition. This template is used, for example, by the SendEmail reactor.

[% USE date %]
[% USE Dumper %]
[% SET user = target.0.usr %]
To: [%- -%]
Subject: Item Due Reminder

Dear [% user.first_given_name %]
[% FOR circ IN target %]
   Title: [%- circ.target_copy.call_number.record.simple_record.title -%]
   Barcode: [% circ.target_copy.barcode %]
   Due: [% circ.due_date %]
[% END %]

[% Dumper.dump(target) %]
Event Environment

Controls which data are available when processing this trigger (Validator, Reactor, Cleanup). Many trigger definitions include usr, target_copy, pickup_lib or target_copy.call_number.record.simple_record. The Event Environment values are paths to objects in the system. This data is stored in action_trigger.environment, bound to action_trigger.event_definition via event_def.

Event Parameters

This allows one to define key/value type data which becomes available during the processing of the trigger (Validator, Reactor). These options may be useful when creating custom validators for example. The Parameter Name can match /[\w,\-\.]+/, but just /\w+/ is more practical. The Parameter Value is eval'd on the server side, so they must be stored as valid Perl values. For strings, wrap them in quotes. This data is stored in action_trigger.event_params, also bound by event_def.

Processing Action Triggers

When events occur records are created in the action_trigger.event table and these events are processed by the script. Usually as a set of cron tasks for the opensrf user.

# General A/T
*/2 * * * * --process-hooks --run-pending

# Run Specific Granularity Only
20 20 * * * --run-pending --granularity Daily-Active-Report --granularity-only

# Just do these hooks
21 21 * * * --run-pending --hooks=checkout

# Example with Wrapper
4 4 * * * /openils/cron/

It's not uncommon to have dozens of entries in the crontab for Evergreen. One may also want to create create wrapper shell scripts for the action_trigger_runner script to permit in-line documentation or other features. Here is an example.

# I'm some documentation on this script!
# Run holds available, only the daily-hold granularity

/openils/bin/ \
  --debug-stdout \
  --verbose \
  --run-pending \
  --hooks=hold.available \
  --granularity=Daily-Hold \
  --granularity-only \
  >/var/log/atr.log \

logger --id --tag atr "Action Trigger Runner for Daily Available Holds Done" 
evergreen-user/action_trigger.txt · Last modified: 2022/02/10 13:34 (external edit)

© 2008-2022 GPLS and others. Evergreen is open source software, freely licensed under GNU GPLv2 or later.
The Evergreen Project is a U.S. 501(c)3 non-profit organization.