Name

global.TaskSLAworkflow

Description

Control the Task SLA workflows. Expects to run after the Task SLA record exists and the record has been updated.

Script

var TaskSLAworkflow = Class.create();

TaskSLAworkflow.prototype = {

  // sys_properties
  SLA_WORKFLOW_LOG: 'com.snc.sla.workflow.log',
  SLA_WORKFLOW_RUN_FOR_BREACHED: 'com.snc.sla.workflow.run_for_breached',
  SLA_DATABASE_LOG: 'com.snc.sla.log.destination',

  initialize : function(taskSLAgr, slaDefGR) {
  	this.runForBreached = (gs.getProperty(this.SLA_WORKFLOW_RUN_FOR_BREACHED, 'false') == 'true');
  	this.taskSLAgr = new GlideRecord(taskSLAgr.getTableName());
  	this.taskSLAgr.get(taskSLAgr.sys_id);

  	if (slaDefGR && slaDefGR.isValidRecord())
  		this.slaDefGR = slaDefGR;
  	else
  		this.slaDefGR = taskSLAgr.sla.getRefRecord();

  	this.lu = new GSLog(this.SLA_WORKFLOW_LOG, this.type);
  	this.lu.includeTimestamp();
  	if (gs.getProperty(this.SLA_DATABASE_LOG, "db") == "node")
  		this.lu.disableDatabaseLogs();

  	// if enable logging has been checked on the SLA definition up the log level to "debug"
  	if (this.slaDefGR && this.slaDefGR.enable_logging)
  		this.lu.setLevel(GSLog.DEBUG);

  	if (this.lu.atLevel(GSLog.INFO))
  		this.lu.logInfo('initialize: with task_sla ' + taskSLAgr.getUniqueValue());
  },

  start: function() {
  	if (!this.taskSLAgr || !this.taskSLAgr.isValidRecord()) {
  		this.lu.logError('start: no Task SLA record supplied');
  		return;
  	}
  	
  	if (!this.slaDefGR) {
  		this.lu.logError('start: no SLA definition supplied');
  		return;
  	}

  	if (this.slaDefGR.workflow.nil()) {
  		if (this.lu.atLevel(GSLog.INFO))
  			this.lu.logInfo('start: no workflow specified on SLA Definition ' + this.slaDefGR.getDisplayValue());
  		return;
  	}
  	
  	if (this.lu.atLevel(GSLog.INFO))
  		this.lu.logInfo('start: copy of workflow ' + this.slaDefGR.workflow + ' started for ' + this.slaDefGR.name);

  	// If the SLA has already breached then unless the appropriate property has been set true don't run the workflow
  	if (this.taskSLAgr.has_breached && !this.runForBreached) {
  		if (this.lu.atLevel(GSLog.INFO))
  			this.lu.logInfo('start: SLA has already breached so workflow will not be started for ' + this.slaDefGR.name);
  		return;
  	}

  	var wfid = this.slaDefGR.workflow + '';

  	var startTime = new GlideDateTime(this.taskSLAgr.start_time.getGlideObject());
  	var now = new GlideDateTime();
  	var msecs = this._truncSeconds(this._calculateRetroAdjust(startTime, now));
  	var scratchPad = {};
  	scratchPad.slaDataJSON = this._getSLADefJSON();
  	scratchPad.timezoneForSchedule = new SLAUtil().getTimezone(this.taskSLAgr);

  	// retroactive, if started more than 5 seconds ago (or due to start in the future)
  	if (msecs <= 0 || msecs > 5000)
  		if (!isNaN(msecs))
  			scratchPad.retroactiveSecsLeft = String(Number(msecs) / 1000);

  	this._startFlow(wfid, this.taskSLAgr, null, scratchPad);
  	this.taskSLAgr.update();
  },

  pause: function() {
  	if (!this.slaDefGR) {
  		this.lu.logError('pause: no SLA definition supplied');
  		return;
  	}
  	
  	if (this.lu.atLevel(GSLog.INFO))
  		this.lu.logInfo('pause: copy of workflow ' + this.taskSLAgr.sla.workflow + ' paused for ' + this.taskSLAgr.sla.name);

  	var wf = new Workflow().getRunningFlows(this.taskSLAgr);
  	while (wf.next())
  		new Workflow().broadcastEvent(wf.sys_id, 'pause');
  },

  resume: function() {
  	if (!this.slaDefGR) {
  		this.lu.logError('resume: no SLA definition supplied');
  		return;
  	}

  	if (this.lu.atLevel(GSLog.INFO))
  		this.lu.logInfo('resume: copy of workflow ' + this.slaDefGR.workflow + ' resumed for ' + this.slaDefGR.name);

  	var wf = new Workflow().getRunningFlows(this.taskSLAgr);
  	while (wf.next())
  		new Workflow().broadcastEvent(wf.sys_id, 'resume');
  },

  stop: function() {
  	if (!this.slaDefGR) {
  		this.lu.logError('stop: no SLA definition supplied');
  		return;
  	}

  	if (this.lu.atLevel(GSLog.INFO))
  		this.lu.logInfo('stop: copy of workflow ' + this.slaDefGR.workflow + ' stopped for ' + this.slaDefGR.name);

  	var wf = new Workflow();
  	wf.cancel(this.taskSLAgr);
  },

  // return the retroactive-start adjustment, in milliseconds.
  _calculateRetroAdjust: function(startTime, now) {
  	var pause = this.taskSLAgr.pause_duration.dateNumericValue();
  	if (this.taskSLAgr.pause_time) {
  		// must be a paused "retroactively starting" SLA, so add on the current period of pause duration (total time, ignoring schedule)
  		var dc = new DurationCalculator();
  		dc.calcScheduleDuration(this.taskSLAgr.pause_time, now); // pause_time may not be a GlideDateTime, let DurationCalculator work it out
  		var extraPause = dc.getTotalSeconds() * 1000;
  		pause += extraPause;
  		if (this.lu.atLevel(GSLog.DEBUG))
  			this.lu.logDebug('extraPause: ' + extraPause);
  	}

  	// allow for accumulated pause_duration on a retroactively starting SLA
  	// by subtracting the pause duration and any current period of pause
  	// (result is -ve, if start is in the future. Don't count pause before an SLA starts)
  	var msecs = now.getNumericValue() - startTime.getNumericValue();
  	if (startTime.compareTo(now) <= 0)
  		msecs -= pause;

  	if (this.lu.atLevel(GSLog.DEBUG))
  		this.lu.logDebug('_calculateRetroAdjust: startTime=' + startTime.getDisplayValueInternal() + '; now=' + now.getDisplayValueInternal() + '; msecs=' + msecs + '; (pause=' + pause + ')');

  	return msecs;
  },

  _truncSeconds: function(ms) {
  	var ri = 1000;
  	return Math.floor(ms/ri)*ri;
  },

  _startFlow: function(workflowId, current, vars, scratchPad) {
  	new SNC.WorkflowScriptAPI().startFlow(workflowId, current, vars, scratchPad);
  },

  _getSLADefJSON: function() {
  	var slaDef = {};
  	
  	if (!this.slaDefGR)
  		return slaDef;

  	slaDef = {
  		name: this.slaDefGR.getValue("name"),
  		duration_type: "" + this.slaDefGR.duration_type,
  		duration: this.slaDefGR.duration.dateNumericValue(),
  		relative_duration_works_on: this.slaDefGR.getValue("relative_duration_works_on"),
  	};
  	
  	return JSON.stringify(slaDef);
  },

  type: 'TaskSLAworkflow'
};

Sys ID

71b05bc90a0a2c39393625f7b47c032c

Offical Documentation

Official Docs: