Skip to content

Scheduling a Process

Reviewed & updated Galland 2023-10-30

This article demonstrates the setting of a process to occur once at a future date.

System Actions are used to schedule a process to occur once, via a ruleset, on a particular document at a particular future date/time.

For example, * A "Case" document has been set to Accepted and saved. * Once the Case is saved, it is required that a scheduled process fires after a number of hours, to check if the Case has been completed. * If the scheduled process finds that the Case is not Completed yet, it should email a supervisor that the Case is taking too long to complete.

System Action

A system action is a special document that is set to run a process once only at a specified future time.

System Action Process

A system action has associated with it the following properties needed to effect a timed process:

Property Description
document/data Data which contains reference to the document on which the action is to occur.
This may contain the entire document structure, but need only contain the documentId of the document.
dueDate Date/time at which the action is to occur.
ruleSet The ruleset to run.

Note, for system actions and schedules to be used in new environments the polling service must be set up. System actions also use the permissions associated with the user who created the action.

Creating a System Action

Aside from schedule system actons, they can be created as a one off event using ft3.createSystemAction(..) function. This allows a ruleset to be run once at a specific time. It can be useful and preferred practise for sending emails or interacting with external web services as it is run in its own container which does not interupt other processes. This function is not available client side.

The function requires the following fields:

Property Description
document/data Document or data which contains reference to the document on which the action is to occur.
dueDate Date/time object or ISO Date string at which the action is to occur.
ruleSet documentId The ruleset documentId to run.
User documentId The logged in user's documentId for auditing purposes.

Example Use in a ruleset:

try {
    const systemAction = await ft3.createSystemAction(
      ntf.document,                         // <----- document
      new Date(),                             // <----- dueDate - scheduled to new Date() 
      'documentId',                         // <---- documentId of the ruleset to run
      ntf.context.user.documentId
    );

    ntf.logger.info("System Action Created: " + systemAction.documentId);
} catch (err) {
        ntf.logger.error(err);
}

It's also worth noting that when a system action is run, it uses the document/data that is stored on the system action. It does not refetch the document when run. If data is changing between the creation of the system action and when it is run, then the updated document should be fetched.

System Action Lifecycle

  • An event on a document calls a corresponding ruleset (eg Case PreSaveServer)
  • This ruleset determines to create a system action for a later date (eg after Case Due Date has passed)
  • The system action is created, referencing both the document and a specific ruleset to run. It sits in the system, waiting to be run.
  • At (or very soon after) the trigger time, the system opens the system action, runs the corresponding ruleset with the original document reference.

Steps to Scheduling a Process

  • Define a System Action Ruleset
  • Script a System Action to use that ruleset

Defining a System Action Ruleset

  • Create a ruleset to run against the particular document type at the scheduled time.
  • Hint -- Be sure to name the ruleset clearly, as there is no other link to indicate the object it is working against. Eg "RKR Case CheckCompleted - OnSystemAction"
    NB -- This is the name used in the call to scheduleNewSystemAction later.
  • There is no need to link the ruleset to the particular document template, as would be required for other events.
  • Be aware, the ruleset will run server side only.

Note The passed document object to the ruleset (ntf.document) will NOT contain the current document as exists in the database; you will need to query for the current document, and perform the process with regard to the new state of the document.

Example Ruleset

// RuleSet: RKR Case CheckCompleted - OnSystemAction
// Updated by: peter.dexter@fieldtec.com 2018-08-17 15:15:30 +10:00
{
#include "JayRule Ruleset Overlay JS",

    ruleset : {
        name : 'RKR Case CheckCompleted - OnSystemAction',

        // ---------------------------------------------------------------------------
        // ruleGetCurrentDocument
        // ---------------------------------------------------------------------------
        ruleGetCurrentDocument : {
            ruleCondition : function(ntf) {
                return (!ntf.currentDocument);
            },

            ruleAction : function(ntf, callback) { 
                var ft3 = ntf.scope; 

                var eqry = {"query": {"bool": {"filter": [
                    {"term" : {"documentId" : (ntf.document.documentId || '0000')}}
                ]}}}; 

                ft3.findDocumentsByElastic(eqry, ntf.user.documentId, function(err, result) {
                    if (err) {
                        ntf.logger.error('Error in query: ' + err.message);
                    }
                    else if (result && result.data && result.data.hits && result.data.hits.total) {
                        ntf.currentDocument = result.data.hits.hits[0]._source;
                        ntf.logger.info('Found current document: ' + ntf.currentDocument.documentId);
                    }
                    else {
                        ntf.logger.error('XXX: No current document found.');
                    }
                    callback(ntf);
                });             
            }
        },

        // ---------------------------------------------------------------------------
        // ruleCheckStatus
        // ---------------------------------------------------------------------------
        ruleCheckStatus : {
            ruleCondition : function(ntf) {
                return (ntf.currentDocument);
            },

            ruleAction : function(ntf) { 
                if (ntf.currentDocument.status !== 'Completed') {
                    ntf.flagNotifySupervisor = true;
                }
            }
        },

        // ---------------------------------------------------------------------------
        // ruleNotifySupervisor
        // ---------------------------------------------------------------------------
        ruleNotifySupervisor : {
            ruleCondition : function(ntf) {
                return (ntf.flagNotifySupervisor);
            },

            ruleAction : function(ntf, callback) { 

                /// ... Send an email to the supervisor

            }
        }
    }
}

Scripting a System Action

Decide on what event you want to schedule a later process (eg on PreSaveServer of a Case).

Write script in the ruleset corresponding to that event, to schedule the calling of the scheduled System Action Ruleset at a future date.

To schedule a System Action, we use scheduleNewSystemAction. (See Function scheduleNewSystemAction )

Syntax

ft3.scheduleNewSystemAction(data, checkDate, objectEventDescriptor, user,
function(systemActionDocument, err) {
    ...
})

Part Description
data the data to pass to the system action ruleset
checkDate the date-time the system action should run
objectEventDescriptor the Name or Object Event Descriptor of the ruleset
user the user to use for the system action
systemActionDocument the newly created system action document
err any error that occurred; null if successful

Example Ruleset

{
#include "JayRule Ruleset Overlay JS",

    ruleset : {
        name : 'RKR Case - PreSaveServer',

        // ---------------------------------------------------------------------------
        // ruleScheduleCompleteCheck
        // If the status is Accepted, generate a system action to check again after 4 hours
        // --------------------------------------------------------------------------
        ruleScheduleCompleteCheck : {
            ruleCondition : function(ntf) { 
                return (
                    ntf.document.status === 'Accepted'    
                );
            },

            ruleAction : function(ntf, callback) { 
                var ft3 = ntf.scope; 

                var nbrMinutesToWait = 240;

                var checkDateM = ft3.moment().add(nbrMinutesToWait, 'minute');
                var checkDate = checkDateM.toDate();
                // OR
                var checkDate = new Date();
                checkDate.setMinutes(checkDate.getMinutes() + nbrMinutesToWait);

                // Create a stripped down version of the document to pass
                var dataToPass = {
                    documentId : ntf.document.documentId,
                    phaseId : '97016732',
                    note : 'document truncated - query for current'
                };

                ft3.scheduleNewSystemAction(docToPass, checkDate, 'RKR Case CheckCompleted - OnSystemAction', ntf.user, function(err, doc) {
                    if (err) {
                        ntf.logger.info(err.message);
                    }
                    else if (doc) {
                        ntf.logger.info('New system action created: ' + doc.documentId);
                    }
                    callback();
                });
            }
        }
    }
}

Note here that the data argument does not need to contain the full document object. It is normally wise that the scheduled process fetch the current document from the server/database when it fires, so we only really need to pass the documentId in the document argument object. Other information can also be passed with the data.