Events

Event Object

Events are non-extensible, script-only accessible un-managed objects that can trigger events and notifications delayed or on a recurring schedule.

When fired, events move into the processing state, and then into the completed or failed state once handled.

Object Properties

  • count { Number readOnly } If recurring, this property will hold the number of times the event was triggered, whether manually or through scheduling.

  • err { Any readOnly } A fault that is recorded if the event handler failed for any reason, threw an error, etc.

  • expiresAt { Date indexed, removable } If set, the event will not trigger once expired and will eventually be garbage collected and deleted by cortex.

  • if { Expression removable } An optional expression that triggers the event if it evaluates to a truey value (!!if()).

  • key { String indexed, unique, removable } An optional unique key up to 512 characters to uniquely identify the event.

  • parent { ObjectID readOnly } Set to the _id of a triggering recurring event.

  • parentKey { String readOnly, indexed } Set to the key of a triggering recurring event.

  • principal { ObjectID } An account or service account used as the calling principal. Can be set using keys and email addresses.

  • retention { Number = never } The retention policy bits. Only affect non-recurring events and children of recurring events.

    • never = 0 - delete the event after it triggers.

    • failed = 1 - retain events that fail.

    • completed = 2 - retain events that complete.

    • skipped = 4 - retain events that were skipped via conditional.

  • schedule { String } A cron format recurrence schedule. Once set, the state is set to scheduled and the start property is set to the next time in the schedule. Recurring events cannot be changed to non-recurring events and vice versa.

  • start { Date = new Date() } The date to trigger the event.

  • started { Date readOnly } The date the event processing was started (or last started int he case of a recurring event).

  • state { Number indexed, readOnly } The current state

    • scheduled = 0 - event is recurring.

    • pending = 1 - event is scheduled to run.

    • processing = 2 - event is currently processing.

    • completed = 3 - event triggered successfully.

    • failed = 4 - an error occurred during processing and was stored in err.

    • skipped = 5 - skipped because a condition was not met.

Object Types

Script

A script event trigger an @on runtime event based on the event and param properties, mirroring the script.fire() functionality. The param value becomes the script.arguments and is also passed as the first argument to the event handler.

  • event { String } The event name that matches a registered runtime event (@on).

  • param { Any } An object passed to the event handler as the first argument.

const { on } = require('decorators')                          

class Events {           

  @on('ns__test')
  static nsTest(param, runtime) {
    // runtime.source === 'event' when fried from an event instance
  }
}

Notification

A notification event sends a notification based on the name, variables and options properties, mirroring the require('notifications').send(...) script functionality.

Because notifications can have multiple endpoints, if more than one error is produced, any additional endpoint errors are added as child faults to the first error.

  • name { String } Notification name. Can be null or missing for custom notifications.

  • variables { Any } Template variables.

  • options { Any } Notification options.

Driver

A driver event runs a db operation based on the options and privileged properties, mirroring the require('db.util').createOperation(options, [options]).execute() script functionality.

Supported operations are: deleteMany, deleteOne, insertMany, insertOne, patchMany, patchOne, updateMany, updateOne.

  • options { Object } Operation options from operation.getOptions().

  • privileged { Boolean = false } If true, privileged options (those only available in-script)

    will be included (skipAcl, roles, grant, bypassCreateAcl).

Console

For testing purposes, a console event outputs param as if console.log(param) were called from a script. Console logging is not available in production environments.

  • param { Any } Max 8KB message to be output.

Constants

return consts.events

/*
{
  "retention": {
    "never": 0,
    "failed": 1,
    "completed": 2,        
    "skipped": 4
  },
  "states": {
    "scheduled": 0,    
    "pending": 1,
    "processing": 2,
    "completed": 3,
    "failed": 4,
    "skipped": 5
    }
  }
*/

Scheduling

To schedule a user event, simply insert an event instance.

When a recurring event - one with a schedule cron - is triggered, it will insert a new event with a pending state with a start date set to the current time, and tick up the count property of the parent.

Error Handling

A err.events.failed trigger is called when an event fails. The trigger context is the event instance, with an additional params (script.arguments) object containing the err object.

const { trigger } = require('decorators')

class ErrorHandling {

  @trigger('err.events.failed')
  handleError({ context, params: { err }}) {

  }

}

Limits

  • configuration.events.softLimit ( Number = 80,000, readOnly ) The number of pending events that can be inserted before the err.events.softLimitExceeded trigger is fired. When fired, configuration.events.triggerSoftLimit is set to false and will not trigger again until reset.

  • configuration.events.hardLimit ( Number = 100,000, readOnly ) The number of pending events that can be inserted before the err.events.hardLimitExceeded trigger is fired. When fired, configuration.events.triggerHardLimit is set to false and will not trigger again until reset. When this threshold is reached, a cortex.invalidArgument.maxAllowed Fault is thrown.

  • configuration.events.triggerSoftLimit ( Boolean = true ) Initially true, this is set to false if the soft limit is triggered and a script trigger exists in the environment runtime. The trigger will not fire again until the property is reset to true. The trigger is always fired inline.

  • configuration.events.triggerHardLimit ( Boolean = true ) Initially true, this is set to false if the hard limit is triggered and a script trigger exists in the environment runtime. The trigger will not fire again until the property is reset to true. The trigger is always fired inline.

// listen for limit triggers

const { trigger } = require('decorators')

class Limits {

  @trigger('err.events.softLimitExceeded')
  onSoftLimit() {
    // time to take a look.
  }

  @trigger('err.events.hardLimitExceeded')
  onHardLimit() {
    // this is an error. events won't insert or recur.    
  }
}

Examples

const { Event } = org.objects,
      { events: { retention: { failed, skipped } } } = consts

// insert a script event to trigger as soon as possible. and retain only if failed or skipped.
Event.insertOne(
  {
    type: 'script',  
    key: 'unique.key',    
    event: 'c_room_room_event',  
    param: {
      anything: 'up to 16kb'
    },
    if: {
      $eq: ['principal._id', script.principal._id]
    },
    retention: failed | skipped
  }
).grant('update').bypassCreateAcl().execute()

// insert a script event to trigger in 24 hours
Event.insertOne(
  {
    type: 'script',  
    key: 'unique.key',    
    event: 'c_room_room_event',  
    param: {
      anything: 'up to 16kb'
    },
    start: new Date(Date.now() + 86400000)
  }
).grant('update').bypassCreateAcl().execute()

// insert a custom notification to be sent once a day at 5am UTC, running as the current principal.
Event.insertOne(
  {
    type: 'notification',
    key: 'scheduled.notif.123',
    principal: script.principal,
    schedule: '0 5 * * *',
    options: {
      endpoints: {
        email: {
          recipients: [          
            'test@example.org',
            ],
          subject: 'Medable',
          message: 'Medable rocks!', // message (plain text) is currently required.
          html: '<html><p>Medable&nbsp;rocks&#33;<p></html>'
        }
      }
    }
  }
).grant('update').bypassCreateAcl().execute()     

// insert a console logger that will run every minute and expire in 5 minutes.
// then, force it to run immediately after scheduling (any recurring event can be 
// set to run manually, but this resets the next time it will run).
Event.insertOne(
  {      
    type: 'console',       
    param: 'foo',
    key: 'scheduled will expire in 5 minutes',
    schedule: '* * * * *',
    expiresAt: new Date(Date.now() + (1000 * 60 * 5))
  }
).grant('update').bypassCreateAcl().execute()


Event.updateOne(
  {
    key: 'scheduled will expire in 5 minutes'
  },
  {
    $set: {
      start: new Date()
    }
  }
).skipAcl().grant('update').execute()

Last updated