One strategy for carrying out actions like LDAP account re-names or other account provisioning actions that depend on prerequisite data is to have IdentityIQ schedule the action to be carried out in a workflow at a future date. This is called "scheduling a workflow event". Under the hood what happens is a new Request object is created and committed to the database. The Request object is of type "Workflow Request", and it carries all of the arguments required to launch the workflow at a future date. Every five seconds the request processor polls the database for new requests that need to be processed. When the "eventDate" of the workflow matches or is behind the current time the request processor will launch the workflow and carry out whatever logic it contains. When the workflow is launched it is is launched in a clean context that is separate from the thread that scheduled the workflow event.
Attached are two example artifacts: an example "hello world" workflow that simply logs the arguments passed to it and stops and the rule that demonstrates how to configure a workflow to be launched at a future date. You can import both of these artifacts into your environment and then run the rule from either the debug page or the console. Five seconds after the rule is executed the request scheduler will launch the workflow. You should see the workflow logs printed in your Identity IQ logs under your application server.
The following illustrates the boilerplate code required to schedule the future launch a Workflow from any block of BeanShell or Rule code. The import statements required are provided in the attached example files. The strings in the example below are designed to be easily edited in the field so you can modify them to substitute in your own variables.
// This rule demonstrates launching a workflow using the Request Scheduler
// features of IdentityIQ 6.2+. This places a Request in the queue to launch
// the specified workflow with the specified arguments. This feature allows
// architects to schedule events to immediately follow Identity refresh
// operations. This takes processing out of Identity refresh tasks and allows
// for more use of the parallelism features in the request processor.
String workflowName = "Hello World Example";
String identityName = "john.doe";
String argumentVal = "CN=john.doe,DC=corp,DC=acme,DC=com";
String caseName = "Run '" + workflowName + "' for: " + identityName;
String requesterId = "spadmin";
Workflow eventWorkflow = context.getObject(Workflow.class, workflowName);
if (null == eventWorkflow) {
log.error("Could not find a workflow named: " + workflowName);
throw new GeneralException("Invalid worklfow: " + workflowName);
}
// Simulate the request being submitted by a user. Default: spadmin.
Identity id = context.getObjectByName(Identity.class, requesterId);
if (null == id) {
log.error("Could not find a requester Identity: " + requesterId);
throw new GeneralException("Invalid identity: " + requesterId);
}
// Ask the Request Processor to start the workflow 5 seconds from now.
// Append the time stamp to the workflow case name to ensure it's unique.
long launchTime = System.currentTimeMillis() + 5000;
caseName = caseName + "(" + launchTime + ")";
// Build out a map of arguments to pass to the Request Scheduler.
Attributes reqArgs = new Attributes();
reqArgs.put(StandardWorkflowHandler.ARG_REQUEST_DEFINITION,
sailpoint.request.WorkflowRequestExecutor.DEFINITION_NAME);
reqArgs.put(sailpoint.workflow.StandardWorkflowHandler.ARG_WORKFLOW,
workflowName);
reqArgs.put(sailpoint.workflow.StandardWorkflowHandler.ARG_REQUEST_NAME,
caseName);
reqArgs.put( "requestName", caseName );
// Build a map of arguments to pass to the Workflow case when it launches.
Attributes wfArgs = new Attributes();
wfArgs.put("identityName", identityName);
wfArgs.put("exampleArgument", argumentVal);
wfArgs.put("workflow", eventWorkflow.getId());
reqArgs.putAll(wfArgs);
// Use the Request Launcher to schedule the workflow reqeust. This requires
// a Request object to store the properties of the request item.
Request req = new Request();
RequestDefinition reqdef = context.getObject(RequestDefinition.class, "Workflow Request");
req.setDefinition(reqdef);
req.setEventDate( new Date( launchTime ) );
req.setOwner(id);
req.setName(caseName);
req.setAttributes( reqdef, reqArgs );
// Schedule the work flow via the request manager.
RequestManager.addRequest(context, req);
Please see the attached example files for more details. When run from the console the rule produces no output unless there is an exception during execution.
In the log file for the application server you an see the following messages from the workflow when it gets launched:
Starting workflow Hello World Example
Variable initialized with launch input: identityName
--> john.doe
Variable initialized with launch input: exampleArgument
--> CN=john.doe,DC=corp,DC=acme,DC=com
Initial case variables:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Attributes PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Attributes>
<Map>
<entry key="exampleArgument" value="CN=john.doe,DC=corp,DC=acme,DC=com"/>
<entry key="identityName" value="john.doe"/>
<entry key="launcher" value="RequestHandler"/>
<entry key="maxThreads" value="12"/>
<entry key="requestDefinition" value="Workflow Request"/>
<entry key="requestName" value="Run 'Hello World Example' for: john.doe(1412087864210)"/>
<entry key="sessionOwner" value="RequestHandler"/>
<entry key="trace" value="true"/>
<entry key="transient" value="false"/>
</Map>
</Attributes>
Starting step Start
Ending step Start
Starting step Middle
2014-09-30 09:37:45,685 DEBUG Thread-8 services.workflow.helloWorld.example:? - Hello World! id:john.doe arg:CN=john.doe,DC=corp,DC=acme,DC=com
Ending step Middle
Starting step End
Ending step End
Ending workflow Hello World Example
Starting in IdentityIQ releases 6.4 and newer, this feature can be exploited to ensure that specific workflow code runs on a specific application server. This mechanism bypasses the concept of "restricted" request processors that was introduced in these versions of IdentityIQ. Request objects can be targeted to a specific Request Scheduler host by specifying the case-sensitive host name of the application server host to run the request on. An example of that API looks like the following:
Request req = new Request();
// ....
// Specify the request get handled by a specific target host.
req.setHost("iiq-ui-server-01.acme.com");
// ...
// continue submitting the request as shown in the example above.
Suman,
I may be wrong, but retries are for running the workflow again if it fails the first time. If your workflow succeeds on the first run then it would not run again.
Instead, you could create two different workflows, one for immediate execution and one scheduled for future execution. That assumes you always want to run twice. You could add logic to the second workflow to check to see if it needs to run.
If you need to maintain state between runs you could create a custom object to preserve the state from the first run so the second run could use it. Make sure you clean up the custom objects when you are through with them.
Regards,
Andrew
The content in this post was very useful with issue we ran into after upgrading to 8.1p3. We rely heavily on delayed requests for processes and after the upgrade to see nothing getting generated was pretty scary. After a few days with support, I came back to make the same response about the getId no longer being valid, however saw it was already here. It would be nice if the change was mentioned in the release notes for 8.1 and up as a known issue to have prevented this scare in the first place.
Are the workflows launched by the beanshell code only able to execute back-end beanshell coe, but not front-end user form?
I tested with a sample workflow which contains the steps of:
Step 1: write some log by beanshell code
Step 2: Present a form for input
This workflow works nice with trigger by QuickLink. However, when this is triggered by "scheduled launch", it could run Step 1 only, with no error on Step 2 (and no output such as work item). This indicates the workflow was successfully executed, but stopped half-way.
Thanks for help!
Is there an example how to use this to send email notificiation ? What is the request def. "Email request" for ?