Saga Documentation 0.9.434-4

Scripts and Jobs

Runnables

Scripts and Jobs share overlapping functionalities, datastructures and concepts. The term runnable refers to this. The name runnable_id used in shared datastructures refers to either a Script or Job. A runnable_call_id refers to an a call or execution of a Script or Job. A runnable_version_id refers to a specific verion of a Script or Job. This is explained in detail below.

See also Scripts and Jobs in web sockets for realtime updates. Runnable Authoring goes into authoring details.

Scripts

A script is node.js code called in a response to an event in SAGA. See Concepts. The path of a script declares what kind of event it responds to and implicitly defines the context of the execution and what variables are available to the script.

NOTE: There can be many script bound to the same path, except for custom http script since they are bound to a URL path.

Property Path

  • /(bots|users|globals)/properties/PROPERTY_NAME - responds to a property with the given name for either bots,users,globals

Available Variables in the script context:

  • parent - either the bot, user or the globals object
  • property - the property object that caused the event

Message Path

  • /users/messages/sent (user, message) - triggered when a user sends a message, even if that message has no recipients
  • /users/messages/incoming (sender, sender_type, user, message) - triggered when a user receives a message
  • /users/messages/outgoing (user, recipient, recipient_type, message) - triggered when a user sends a message, once for each user -> recipient pair
    • For example, if user A sends a message to user B and bot B, this script will be triggered twice, for user A -> user B, and user A -> bot B
  • /bots/messages/sent (bot, message) - triggered when a bot sends a message, even if that message has no recipients
  • /bots/messages/incoming (sender, sender_type, bot, message) - triggered when a bot receives a message
  • /bots/messages/outgoing (bot, recipient, recipient_type, message) - triggered when a bot sends a message, once for each bot -> recipient pair
    • For example, if bot A sends a message to user B and bot B, this script will be triggered twice, for bot A -> user B, and bot A -> bot B

Available variables in the script context (changes depending on the path):

  • sender - either a user or a bot, depending on sender_type
  • sender_type - either 'User' or 'Bot'
  • recipient - either a user or a bot, depending on recipient_type
  • recipient_type - either 'User' or 'Bot'
  • user - the given user
  • bot - the given bot
  • message - the message object

User Lifecycle Event Path

  • /users/events/create - user was created
  • /users/events/verify - user has been verified
  • /users/events/login" - user logged in
  • /users/events/change_password_request - user wants to change password
  • /users/events/change_password_verified - users password has been changed
  • /users/events/change_email_request - user wants to change email
  • /users/events/change_email_verified - users email has been changed

Available Variables in the script context:

  • user - the given user

Custom HTTP Path

  • /requests/post/PATH - A HTTP post custom script call with the given path
  • /requests/get/PATH - A HTTP get custom script call with the given path
  • /requests/delete/PATH - A HTTP delete custom script call with the given path

The path is mounted at API_ROOT/requests/, the HTTP method is post, get or delete depending on the path.

Available Variables in the script context:

  • request - the Node HTTP Request Object
  • response - the Node HTTP Response Object
  • user - if the script requires an authenticated user

The actual URL for the given HTTP method is

https://API_DOMAIN/requests/PATH

Filters

The field parent_properties_criteria let's you specify a list of properties the parent has to have for the script to apply. The parent properties becomes a positive or a negative dependency. This does not apply for custom HTTP Scripts.

  • ["home"] - the script applies only if the parent user or bot has a home property
  • ["!exit"] - the script applies only if the parent user or bot doesn"t have a exit property
  • ["!exit","home"] - the script applies only if the parent user or bot doesn"t have a exit property and must have a home property

The field parent_name_criteria lets you specify the names of the bot or user to match or not, you can't mix in this case.

  • ["rob","hans"] - script only applies to users ar bots with the name rob or hans
  • ["!dominik"] - script is excluded from the user with the name dominik

The field boolean requires_user is applicable for custom HTTP Scripts only, if true the script requires

GET /scripts

List all scripts. Each script has

  • title - a title
  • notes - notes to explain the object etc
  • path - the path
  • enabled - whether the script is enabled
  • logging - whether the scripts logging is captured
  • javascript - the javascript code that is executed when the trigger matches.
  • debug - if true all console.log statements are stored in the database.
  • parent_name_criteria - the parent_name_criteria
  • parent_properties_criteria - the parent_properties_criteria

Query Parameters

  • fields (optional):
    • command separated list of names of fields to be returned
      • title
      • title,path
[
 {
    "_id": "55999d97bb067fcf2c06ff57",
    "title": "room count",
    "path": "/users/properties/room",
    "enabled": "true",
    "javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()",
    "logging": true,
    "parent_properties_criteria": ["criteria"] 
  },
 {
    "_id": "55999d97bb067fcf2c06ff57",
    "title": "weather reflector",
    "path": "/globals/properties/weather",
    "enabled": "false",
    "javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()",
    "logging": false,
    "parent_properties_criteria": [] 
    
  }
]

POST /scripts

Create a script.

  • title - a title
  • path - see above
  • logging - whether the scripts logging is captured
  • javascript - the javascript code that is executed when the trigger matches.
  • parent_name_criteria - the parent_name_criteria
  • parent_properties_criteria - the parent_properties_criteria

 {
    "title": "room count",
    "path": "/users/properties/room",
    "javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()",
    "parent_properties_criteria": ["criteria"],
     "parent_name_criteria": ["leo"]     
}

GET /scripts/:id

Get the script with the given :id.

  • title - human-readable title
  • notes - notes to explain the object etc
  • path - see above
  • enabled - whether the script is enabled
  • javascript - the javascript code that is executed when the trigger matches.
  • parent_name_criteria - the parent_name_criteria
  • parent_properties_criteria - the parent_properties_criteria

Query Parameters

  • fields (optional):
    • command separated list of names of fields to be returned
      • title
      • title,path
 {
    "_id": "55999d97bb067fcf2c06ff57",
    "title": "weather reflector",
    "enabled": "true",
    "path": "/properties/weather",
    "javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()"
  }

UPDATE /scripts/:id

Update the script with the given :id. 'errorMessages', 'errorInvocationCount' and 'invocationCount' are not reset.

  • title - title
  • path - see above
  • enabled - whether the script is enabled
  • javascript - the javascript code that is executed when the trigger matches.
  • notes - notes to explain the object etc
  • parent_name_criteria - the parent_name_criteria
  • parent_properties_criteria - the parent_properties_criteria
 {
    "title": "room count",
    "path": "/users/properties/room",
    "verb": "put",
    "javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()"
}

DELETE /scripts/:id

Update the script with the given :id

Jobs

A job is node.js that is called on a given schedule. A schedules is declared using the [later.js text syntax](http://bunkat.github.io/later/parsers.html#text. The overall structure is very similar to scripts, but instead of path a job has a text_schedule that defines how frequent it will be invoked. There are no implicit variables passed to the job since there is no other context then time.

GET /jobs

Returns all jobs.

  • title - a title
  • text_schedule - a text description of the schedule using later.js text syntax.
  • enabled - whether the job is enabled
  • logging - whether the scripts logging is captured
  • javascript - the javascript code that is executed when the trigger matches. NOTE: More to come about restrictions and context.

Query Parameters

  • fields (optional):
    • command separated list of names of fields to be returned
      • title
      • title,path
[
 {
    "_id": "55999d97bb067fcf2c06ff57",
    "title": "room count",
    "enabled": "true",
    "text_schedule": "every 5 minutes",
    "javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()",
  },
 {
    "_id": "55999d97bb067fcf2c06ff57",
    "title": "weather reflector",
    "false": "true",
    "path": "every 2 days",
    "javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()"
  }
]

POST /jobs

Create a job.

Required fields:

  • title - a title
  • enabled - whether the job is enabled
  • text_schedule - a text description of the schedule using later.js text syntax.
  • javascript - the javascript code that is executed when the trigger matches.
  • notes - notes to explain the object etc
{
  "_id": "55999d97bb067fcf2c06ff57",
  "title": "room count",
  "text_schedule": "every 5 minutes",
  "javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()"
}

GET /jobs/:id

Get the jobs with the given :id.

  • title - a title

  • text_schedule - a text description of the schedule using later.js text syntax.

  • enabled - whether the job is enabled

  • javascript - the javascript code that is executed when the trigger matches.

  • notes - notes to explain the object etc

Query Parameters

  • fields (optional):
    • command separated list of names of fields to be returned
      • title
      • title,path
{
  "_id": "55999d97bb067fcf2c06ff57",
  "title": "room count",
  "text_schedule": "every 5 minutes",
  "javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()",
}

PUT /jobs/:id

Update the jobs with the given :id.

Possible fields:

  • title - a title
  • enabled - whether the job is enabled
  • text_schedule - a text description of the schedule using later.js text syntax.
  • javascript - the javascript code that is executed when the trigger matches.
  • notes - notes to explain the object etc
{
  "_id": "55999d97bb067fcf2c06ff57",
  "title": "room count",
  "text_schedule": "every 2 minutes",
  "javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()",
}

DELETE /jobs/:id

Delete the jobs with the given :id.

{
  "_id": "55999d97bb067fcf2c06ff57",
  "title": "room count",
  "text_schedule": "every 2 minutes",
  "javascript": "(function(){GlobalProperty.findOrCreate({name:'roomEnter'}).then(function(property){ GlobalProperty.addValue('roomEnter',property.parent,null,false);})})()"
}

Versions

Each post or update of the javascript code of a Script or Job automatically creates a version entry.

GET /jobs/:id/versions

GET /scripts/:id/versions

Returns a list of all versions for the given script or job. Each entry contains the following.

  • _id - the version id
  • runnable_id the script or job id
  • user_id the id of the user that authored the change
  • javascript the actual code of the version

Example

[
    {
        "_id": "60c41b37b3dca300384aad59",
        "runnable_id": "574c9ac8e1e8d2030017c96d",
        "user_id": "60b68ee8a4150d0020c1eede",
        "javascript": "console.log("hello world);,
        "createdAt": "2021-06-12T02:25:59.586Z",
    }
]

Activity

Each script or job invocation is stored as a RunnableCall object. A runnable is the internal base object for bot Scripts and Jobss, hence the name RunnableCall.

  • _id - the id of the call
  • has_error_message - true if the call resulted in an error
  • duration the execution duration in milliseconds
  • queue_duration the queue duration in milliseconds
  • runnable_id the id of either the script or job
  • runnable_version_id the version of the script or used in the call, see [Versions]
  • runnable_type 0=job, 1=script
  • createdAt the time stamp
  • runnable_logs array containing the values logged during the call

Script calls contain additional information depending on the type.

  • parent_id "60bf52a2dbd52e0069edcb35",

  • property_id "60de2461a94d9608f8160c15",

  • parent_object {

  • _id "60bf52a2dbd52e0069edcb35",

  • name "solarboy" },

}

GET /jobs/:id/logs

GET /scripts/:id/logs

Returns a pageable list of logging statements created by the given script or job via console.log. 'runnable_call_id' refers to the runnable call object that stores information about the job execution. Logs are only stored if the script or job is set to debug:true.

Important fields:

  • createdAt - timestamp
  • runnable_id - the id of the job or scripts
  • runnable_call_id - the id of the specific call that triggered the script or job that created the log
  • messages - the logging message. console.log(1,2,3) will create [1,2,3]. multiple console.log calls will create multiple object
  • level - the log level, info, error or log
[
  {
      "_id": "5a53ff5cfdc0196880dc8cb4",
      "createdAt": "2018-01-08T23:31:40.612Z",
      "updatedAt": "2018-01-08T23:31:40.612Z",
      "runnable_id": "5706caaebb6fba08718e2e9c",
      "runnable_call_id": "5a53ff5cfdc0196880dc8cb2",
      "level": "log",
      "messages": ["object",{"name":"me"}],
      "__v": 0,
      "id": "5a53ff5cfdc0196880dc8cb4"
  }, {
      "_id": "5a53ff3efdc0196880dc8c7c",
      "createdAt": "2018-01-08T23:31:10.552Z",
      "updatedAt": "2018-01-08T23:31:10.552Z",
      "runnable_id": "5706caaebb6fba08718e2e9c",
      "runnable_call_id": "5a53ff3efdc0196880dc8c7a",
      "level": "log",
      "messages": ["here 1"],
      "__v": 0,
      "id": "5a53ff3efdc0196880dc8c7c"
  }
]

GET /jobs/:id/calls

GET /scripts/:id/calls

Returns a pageable list of meta data associated with a script or job execution.

Important fields:

  • createdAt - timestamp
  • duration - time in milliseconds it to for the script execution
  • runnable_id - the actual runnable that object here is describing
  • tpye - scripts or jobs
  • parent - the owner of the property that invoked the runnable, only applicable to bots and users
  • property_id - the property that caused the script invocation, , only applicable to scripts

[
  {
      "_id": "5a5e52fedb9ebb774b998415",
      "createdAt": "2018-01-16T19:31:10.353Z",
      "updatedAt": "2018-01-16T19:31:10.673Z",
      "duration": 322,
      "runnable_id": "5706caaebb6fba08718e2e9c",
      "type": "scripts",
      "parent_id": "588a380faaaaaec3f4e65d2b",
      "property_id": "5a5e52fec6e312774a4d1ad7",
      "__v": 0,
      "id": "5a5e52fedb9ebb774b998415"
  }, {
      "_id": "5a5e52a5db9ebb774b9983ea",
      "createdAt": "2018-01-16T19:29:41.270Z",
      "updatedAt": "2018-01-16T19:29:41.479Z",
      "duration": 209,
      "runnable_id": "5706caaebb6fba08718e2e9c",
      "type": "scripts",
      "parent_id": "588a380faaaaaec3f4e65d2b",
      "property_id": "5a5e52a5c6e312774a4d1abb",
      "__v": 0,
      "id": "5a5e52a5db9ebb774b9983ea"
  }
]

GET /jobs/:id/version

GET /scripts/:id/version

Every time a script or job is updated the old version is saved in history for basic version management.

Important fields:

  • createdAt - timestamp
  • runnable_id - the actual runnable that object here is describing
  • javascript - the actual code of this version
  • old_javascript - the code of the prior version, allows for easy code diffs.
[{
    "_id": "5a5d78878c7b559d56c58be0",
    "createdAt": "2018-01-16T03:59:03.750Z",
    "updatedAt": "2018-01-16T03:59:03.750Z",
    "runnable_id": "56129b834f0d7cce5e098fbe",
    "javascript": "...",
    "old_javascript": "...",
    "__v": 0,
    "id": "5a5d78878c7b559d56c58be0"
}, {
    "_id": "5a5d787b8c7b559d56c58bde",
    "createdAt": "2018-01-16T03:58:51.939Z",
    "updatedAt": "2018-01-16T03:58:51.939Z",
    "runnable_id": "56129b834f0d7cce5e098fbe",
    "javascript": "",
    "old_javascript": "...",
    "__v": 0,
    "id": "5a5d787b8c7b559d56c58bde"
}]

GET /scripts/:id/reset

Resets the runtime statistics of the script, the values are 'errorMessages','errorInvocationCount' and 'invocationCount'

Next: WebSockets