The Now Platform® Washington DC release is live. Watch now!
on 08-09-2020 10:01 PM
Hi there,
With Workflows, I'm used to taking shortcuts on the testing. Especially when it comes to times… you are not going to wait for days until time passes? Or changing your workflow temporarily so it uses a shorter time?
So what about Flows? How can you shortcut testing on Flow Designer and for example "Wait for a duration of time"?
Workflow
One of the possibilities to shorten testing on Workflow timers would be to locate the Schedule record [sys_trigger] involved. You could simply update the Next action [next_action], so you don't have to wait for hours/days.
Flow Designer
While testing some Flows I thought, let's take the same shortcut as I usually do while testing Workflows. Though… Flows don't seem to be using Schedule records as Workflows do. It took me while searching (and looking back the search could be shortened a lot…), though found a way!
Events [sysevent]
When using for example "Wait for a duration of time" within your Flow, an Event record will be generated. The Event record can be identified while filtering on "name=flow.fire, queue=flow_engine". Because you are after future Events, also filter on "state=ready".
name=flow.fire^queue=flow_engine^state=ready
Depending on how many Flow Executions are active, this could be a lengthy list obviously. You might already identify the Event you are after based on the dates and Parm1, though more reliable: copy the sys_id value from your active flow (obtain it for example through "Flow Designer > Active Flows") and filter in the Events table on instance=sys_id.
Event: Process on
So the trick to speed up testing… Field Process on [process_on]. You could just update the value of this field, similar to doing for the Next action on Schedule records for Workflows!
And that's it actually. Once you know this, so easy… And actually, when searching in your Navigator for Flow Designer, notice there's an Event Queue module listed. You just have to add the Process on the field to the List opened through this module.
---
And that's it actually. If any questions or remarks, let me know!
If this post helped you in any way, I would appreciate it if you hit bookmark or mark it as helpful. Interested in more articles, blogs, videos, and Share projects on Flow Designer I published? - Flow Designer |
Kind regards,
Mark
2020 ServiceNow Community MVP
2020 ServiceNow Developer MVP
---
Thanks for sharing Mark! This is exactly what I needed today.
I faced this challenge before I've found your article. I used different angle in my case: I've created a custom action that was used whenever the flow would wait. The action was simply checking which instance the flow is running using:
gs.getProperty('instance_name');
and if it was DEV or TEST instance the wait time was decreased to e.g. 1 minute.
huge PP man, this saved me quite some time!
Hi Mark,
I believe this is what I need to complete my Flow designer process but i not sure of the event set up. I believe this will help with me creating an execution plan for the fulfillment process in my Flow designer.
So my question is?
Do i need both step above in order for my Flow designer to work?
Right now, my Flow designer pause or waiting. I not sure why it will not go through the complete Flow designer process.
I place a screen shot of my issue
Please help !
lol
lbinghamone@comcast.net
Hi there,
Please post this as a question within the community. You'll likely get more reply posting it as a question, than when you are responding to an article (which is about something else).
Kind regards,
Mark
This no longer appears to be the case with the Rome release. I used to do this all the time - go to the event queue, update the "Process On" field for my flow during testing - but now, the "Waiting" action on a Flow no longer appears to generate an event.
Anyone else experience this?
I experienced the same thing, but I found a workaround!
Find an example event with parm1 that looks like:
<flowname>.75f7da0cdb7a8110d02bfb2439961963.41ceca4187120010663ca1bb36cb0b06.If$1.Wait For Condition Check.If$1.Wait For Condition.If$1.Wait For Condition Wait./monitor/operation
Modify the last section of the parm1 to look like:
<flowname>.75f7da0cdb7a8110d02bfb2439961963.41ceca4187120010663ca1bb36cb0b06.If$1.Wait For Condition Check.If$1.Wait For Condition.If$1.Wait For Condition Wait./condition/complete
Also set the state to Ready, and clear the Processed field, and then do an insert and stay.
And then it force completed the Flow. The key bit is that "condition/complete" at the end, seems like those are the magic words.
Dang, not seeing any events like that for the "Wait for relative duration" actions. Is yours only for "Wait for condition" actions?
I'm using the OOTB "Wait for condition" action with the "Enable timeout" box checked, and I tested either with a set duration, or a scripted duration based on a field (to set the number of seconds).
The events are on the Event "sysevent" table with the name of like "flow.fire".
I was testing on a Rome Patch 7 instance.
Actually I figured out where they pop up now!
If you want to speed up a "Wait for duration" action, go to System Scheduler > Scheduled Jobs > Today's Scheduled Jobs.
Add a filter of "Name = flow.fire" and "Script CONTAINS ______" (the sys_id of your flow execution).
If you change the "Next Action" date/time to the current date/time, it will then create the event that we used to see. Then if you update the "Process on" date/time on that event, then the flow will finally keep going!
This is great information, exactly what I am looking for to speed up the 'wait for duration' step in Flow Design. Cheers
Jan 2023 - Process that I followed on Tokyo version that worked successfully to cancel a timer in a flow (catalog request):
1. goto table sys_trigger, look for record named flow.fire created in the last few minutes (or the time that your flow action for the timer was started), where the next action field aligns with the timer expiration time (x time in future). Once you identify the target sys_trigger record, set the next action field to the current date and time and save the record.
example:
https://<instance-name>.service-now.com/sys_trigger_list.do?sysparm_query=sys_created_onONLast%2045%20minutes%40javascript%3Ags.beginningOfLast45Minutes()%40javascript%3Ags.endOfLast45Minutes()%5Ename%3Dflow.fire
2. got table sysevent. ensure the column "process on" is visible in list. Find the event "flow.fire" where param1 starts with the catalog item name that belongs to the target flow with the timer to be cancelled - set the state field to "processed" and save the record.
https://<instance-name>.service-now.com/sysevent_list.do?sysparm_query=sys_created_onON2023-01-19%40javascript%3Ags.dateGenerate('2023-01-19'%2C'start')%40javascript%3Ags.dateGenerate('2023-01-19'%2C'end')%5EnameSTARTSWITHflow.fire
here is the code to do this via script if anyone wants to cancel flow timers from ATF
var target_ritm = 'RITM5317565'; // change this
var gr2, gr3, gr4;
var flow_name = '';
var flow_context_sysid = '';
var gr1 = new GlideRecord("sc_req_item");
gr1.addQuery("number", target_ritm);
gr1.query();
if (gr1.next()) {
flow_context_sysid = gr1.getValue("flow_context");
gs.print('cancel active timer on flow context: ' + flow_context_sysid);
// get flow name
var gr2 = new GlideRecord('sys_flow_context');
if (gr2.get(flow_context_sysid)) {
flow_name = gr2.name + '';
// look for related entries in sys_trigger
// created on last 15 mins and name is flow.fire, and job context contains flow name
// https://metdev.service-now.com/sys_trigger_list.do?sysparm_query=sys_created_onONLast%2015%20minutes%40javascript%3Ags.beginningOfLast15Minutes()%40javascript%3Ags.endOfLast15Minutes()%5EnameSTARTSWITHflow.fire%5Ejob_contextLIKEreturn%20asset&sysparm_view=
gr3 = new GlideRecord('sys_trigger');
// gr3.addEncodedQuery('sys_created_onONLast 15 minutes@javascript:gs.beginningOfLast15Minutes()@javascript:gs.endOfLast15Minutes()');
gr3.addEncodedQuery('sys_created_onONLast 2 hours@javascript:gs.beginningOfLast2Hours()@javascript:gs.endOfLast2Hours()');
gr3.addEncodedQuery('nameSTARTSWITHflow.fire^job_contextLIKE' + gr2.name);
gr3.query();
if (gr3.next()) {
gs.print('trigger found: ' + gr3.job_context);
gr3.next_action = gs.nowDateTime();
gr3.update();
} else gs.print('no matching trigger found');
gs.sleep(5000); // wait 5 sec for flow processing
// look for entries in sysevent related to the timer that need to be cancelled
var gr4 = new GlideRecord('sysevent');
// gr4.addEncodedQuery('sys_created_onONLast 15 minutes@javascript:gs.beginningOfLast15Minutes()@javascript:gs.endOfLast15Minutes()');
gr4.addEncodedQuery('sys_created_onONLast 2 hours@javascript:gs.beginningOfLast2Hours()@javascript:gs.endOfLast2Hours()');
gr4.addEncodedQuery('table=sys_flow_context');
gr4.addEncodedQuery('state!=processed^ORstate=^name=flow.fire^parm1LIKE' + flow_name + '^instanceSTARTSWITH' + flow_context_sysid);
gr4.query();
if (gr4.next()) {
gs.print('event to be cancelled was found: ' + gr4.parm1);
gr4.process_on = gs.nowDateTime();
gr4.update();
}
else gs.print('no matching event found to be cancelled');
} // end flow context check
}
I actually wrote a little custom action to force complete a wait for duration. Works similarly to kevinandersons, but I figured I would post it. I've tested mine up through San Diego.
Force Complete Wait for Duration
(function execute(inputs, outputs) {
var flowcontext = inputs.flowcontextid + '';
var resultID = 'NULL';
if (flowcontext === 'null' || flowcontext === '') {
return;
}
//find the queued up flow.fire sys_trigger job
var grTrigger = new GlideRecord('sys_trigger');
grTrigger.addQuery('name', 'flow.fire');
grTrigger.addQuery('script', 'CONTAINS', flowcontext);
grTrigger.addQuery('job_context', 'CONTAINS', '/timer/complete_duration');
grTrigger.addQuery('state', 0);
grTrigger.setLimit(1);
grTrigger.query();
if (grTrigger.next()) {
var gr = new GlideRecord('sysevent');
gr.initialize();
gr.setNewGuid();
gr.setValue('name', 'flow.fire');
gr.setValue('queue', 'flow_engine');
gr.setValue('parm1', grTrigger.getValue('job_context').toString().slice(6)); //strips off the first part, parm1=
gr.setValue('parm2', '');//couldn't figure out what ID they use, but it doesn't seem necessary..
gr.setValue('instance', flowcontext);
gr.setValue('table', 'sys_flow_context');
gr.setValue('state', 'ready');
gr.setValue('process_on', new GlideDateTime().getValue()); //aka run immediately
resultID = gr.insert();
grTrigger.deleteRecord();
}//else will return an error - no timer job found
outputs.result_id = resultID;
})(inputs, outputs);
I also wrote another script for force completing Wait for Condition
Force Complete Wait for Condition
(function execute(inputs, outputs) {
var flowcontext = inputs.flowcontextid+'';
var resultID = 'NULL';
//lookup the most recent sysevent
var grEventModel = new GlideRecord('sysevent');
grEventModel.addQuery('instance',flowcontext);
grEventModel.addQuery('parm1','CONTAINS','monitor/operation');
grEventModel.orderByDesc('process_on');
grEventModel.setLimit(1);
grEventModel.query();
if(grEventModel.next()){
//Create a new event to force complete it
var gr = new GlideRecord('sysevent');
gr.initialize();
gr.setNewGuid();
gr.setValue('name', 'flow.fire');
gr.setValue('queue', 'flow_engine');
var newParm1 = (grEventModel.getValue('parm1')+'').replace("monitor/operation", "condition/complete");
gr.setValue('parm1', newParm1);
gr.setValue('parm2', grEventModel.getValue('parm2'));
gr.setValue('instance', flowcontext);
gr.setValue('table', 'sys_flow_context');
gr.setValue('state', 'ready');
gr.setValue('process_on', grEventModel.getValue('process_on'));
resultID = gr.insert();
}//else will Return an error... No timer found
outputs.result_id = resultID;
})(inputs, outputs);