Parallel flow -> multiple Approval Activity skipping

bryanjurgensmey
Kilo Contributor

Here's my use case:

When a new record is added to pc_software_cat_item run an Approval Activity for each Company using our instance.   If approved the item is added to their employee user criteria so that it becomes available in Portal.   Each company can choose to approve or deny and they're independent of each other.

The issue:

I can create ~20 stand-alone workflows (1 per company) and it works, however, ideally this would be dynamic and just need 1 workflow that accepts param's for the approval group and user criteria record.  

This seemed like a good use case for Parallel Flow so I created a workflow (New Catalog Item Approval - Parent) that runs a Parallel Flow Launcher for my approval workflow (New Catalog Item Approval).   I'm triggering this with an on-after business rule and passing an input with the array containing an approval group and the user criteria record from the parent workflow to the approval workflow.   This works and the inputs are correctly passed, however, only 1 instance of the approval activity will hold 'executing' and the rest just skip (attached).   The skipped workflows are receiving correct inputs.

I added the timer, which does seem to occasionally allow more than 1 flow to stay executing but I have no idea why that helps.

Any idea's why this is failing?

19 REPLIES 19

Sure, it should be OOB except for the 2 additions made per your article:

 

var WFCreateTaskActivityUtils = Class.create();
WFCreateTaskActivityUtils.prototype = Object.extendsObject(WFActivityHandler, {

initialize: function() {
WFActivityHandler.prototype.initialize.call(this);
},

execute: function() {
// did we pre-generate the task?
var taskID;
var genObj = this._getGenerateObj(activity.activity.toString());
if (genObj && genObj.taskID) {
taskID = genObj.taskID;
if (!this._setTaskState(taskID, '1'))
return;
} else
taskID = this._createTask('1');

return taskID;
},

_getExistingTask: function() {
var task = new GlideRecord(activity.vars.task_table);
task.initialize();
task.addQuery('parent', current.sys_id);
task.addQuery('wf_activity', activity.activity.sys_id);
task.addQuery('u_wf_context', activity.context.sys_id); // Custom fix for parallel flow
task.query();
if (task.next())
return task;

return null;
},

_createTask: function(state, order, startAt, noCreateFlag) {
var task = this._getExistingTask();
if (task) {
task.state = state;
if (startAt)
task.expected_start.setValue(startAt);
else
task.expected_start = gs.nowDateTime();

this._setDueDate(task, startAt);
if (!noCreateFlag)
task.update();

return task.sys_id.toString();
}
task = new GlideRecord(activity.vars.task_table);
task.initialize();
this._setReferences(task);
task.state = state;
if (order) {
task.order = order;
}

if (startAt) {
task.expected_start.setValue(startAt);
} else {
task.expected_start = gs.nowDateTime();
}

this._setDueDate(task, startAt);
this._setValues(task);
if ((activity.vars.task_table == 'sc_task') && (current.getRecordClassName() == 'sc_req_item'))
task.request_item = current.sys_id;

if ((activity.vars.task_table == 'change_task') && (current.getRecordClassName() == 'change_request')){
task.change_request = current.sys_id;

if(gs.getProperty('glide.workflow.create_task.set_created_from_workflow', 'false') == 'true')
task.created_from = 'workflow';
}

if ((activity.vars.task_table == 'problem_task') && (current.getRecordClassName() == 'problem'))
task.problem = current.sys_id;

if ((activity.vars.advanced == true) && (activity.vars.advanced_script))
this._setAdvanced(task);

if (noCreateFlag)
return "";

task.wf_activity = activity.activity.sys_id;
task.u_wf_context = activity.context.sys_id; // Custom fix for parallel flow launcher
return task.insertOrUpdate('sys_id');
},

_setReferences: function(task) {
task.parent = current.sys_id;
},

_setTaskState: function(taskID, state) {
var gr = new GlideRecord('task');
if (!gr.get(taskID)) {
executing.result = 'deleted';
return false;
}

gr.state = state;
gr.update();

// a business rule might cause the task to be closed when we open it, so check this condition
if (!gr.active)
executing.result = gr.state;

return gr.active;
},

_setDueDate: function(task, startAt) {
var wd = new WorkflowDuration();
wd.setActivity(this);
wd.setStartDateTime(startAt);
wd.setWorkflow(context.schedule, context.timezone);
wd.calculate(activity.vars.__var_record__);
task.due_date.setValue(wd.getEndDateTime());
this.duration = wd.getTotalSeconds() * 1000;
},

_setValues: function(task) {
var type = activity.vars.task_value_type;
if (type == 'Fields')
this._setValuesFromFields(task);
else if (type == 'Template')
this._setValuesFromTemplate(task);
else if (type == 'Values')
this._setValuesFromValues(task);

if(task.priority.nil())
task.priority = activity.vars.task_priority;
},

_setValuesFromFields: function(task) {
task.assignment_group = activity.vars.task_fulfillment_group;
task.assigned_to = activity.vars.task_assigned_to;
task.short_description = activity.vars.task_short_description;
task.description = activity.vars.task_instructions;
},

_setValuesFromTemplate: function(task) {
var t = GlideTemplate.get(activity.vars.task_template.toString());
t.apply(task);
},

_setValuesFromValues: function(task) {
task.applyEncodedQuery(activity.vars.task_set_values);
},

_setAdvanced: function(task) {
var oldTask = workflow.getScriptVariable('task');
workflow.prepareScriptVariable('task', task);
this.runScript(activity.vars.advanced_script);
workflow.prepareScriptVariable('task', oldTask);
},

type: 'WFCreateTaskActivityUtils'
});

The code is as expected, can you send a print screen of the workflow? I will try to see if I can reproduce your bug.

Also, can you make sure that the u_wf_context field is filled with the proper value on your catalog task. You can check with a Show XML on the catalog task.

If the value is as expected in the u_wf_context field (it should refer to the workflow context associated with the task), you could try to set a breakpoint in the _createTask function (line 36), then open up the Script debugger and get to the point in the workflow that does not create the task. You can then check if the code is able to find a task or not, usually for a new task to be created it should not find any task at line 36.

You can also add a breakpoint at line 19 and check the value of the taskID variable, it should contains the sys_id of the task, you can then check in the sc_task table to see what task this sys_id is matching, if it's the sys_id of the existing task, that means that somehow the query for existing task is not working as expected. If you're not finding any task with that sys_id or if the value is null, it would mean that there is a problem during the insertion of the task.

Here is the workflow,everything with a green box seems to be working, but the remaining tasks are not being generated.

find_real_file.png

The same thing happens within the workflow being started through the Parallel Flow Launcher.

It also appears that the new field u_workflow_context is not being populated on the task which is created:

<u_verify>false</u_verify>
<u_workflow_context/>
<universal_request/>
<upon_approval>proceed</upon_approval>
<upon_reject>cancel</upon_reject>
<urgency>3</urgency>
<user_input/>
<variables/>
<watch_list/>
<wf_activity display_value="CMDB Operations - Foundation data">d1b856e41b040d10450742a7bc4bcb9c</wf_activity>
<work_end>2021-11-22 21:58:34</work_end>
<work_notes/>
<work_notes_list/>

I will try to follow your recommended debugging steps to see if I can determine what's going on.

 

Hi Kent, the field should be named u_wf_context for it to work. Based on your XML you took the column name u_workflow_context.

Try to recreate the column and give the column name u_wf_context or you can also update the scripts and use u_workflow_context in your scripts instead of u_wf_context.

If it still doesn't work following the fix of the column name, I'll investigate with the provided workflow example.

Hi Laurent,

Thanks for catching that mistake I made, this is now working beautifully!!! I'm going to continue to test, but I think this is a great customization which seems to resolve ServiceNow deficiencies using the Parallel Flow Launcher (it's a shame they haven't made this update).

I'll let you know if I run into any other issues, Thanks so much for your assistance!

You should really write this up as a complete article, I'm sure we are not the only ones that could benefit greatly from the work you have done!

Kind Regards,

Kent Harwell