Deferred Operations
To asynchronously run operations that require long processing times in the background, you can use deferred operations. When you call this type of operation, a unique identifier is returned, and processing starts to run in the background. You can use the unique identifier later on to check the status of the operation and get the results.
Call Deferred Operation
You call deferred operations in the same manner as regular operations. The only difference is that deferred operations return a UUID that you use to check operation status.
GET https://localhost:8080/asynchronous_operation
Return
ce106553-fe04-405b-b452-096928632c30
Query Deferred Operation Status
After you call a deferred operation, you use the returned UUID to check processing status and get the results. To do so, call the operation with the iop_deferred_operation_id parameter set to the UUID value.
GET https://localhost:8080/asynchronous_operation?iop_deferred_operation_id=ce106553-fe04-405b-b452-096928632c30
Return Values
Return Code
|
Meaning
|
202
|
Operation running.
|
500
|
Operation failed.
|
410
|
Operation does not exist, or its results have been deleted.
|
200
|
Operation successful. Results appear in response body.
|
Implement Deferred Operations With Results Checking
To implement deferred operations with results checking in Groovy, you can use the com.servicemax.core.asynchronous_operation.AsynchronousOperation class. When you define deferred operations, specify execute as the executing method and make the class that implements the operation a subclass of AsynchronousOperation. Subclasses of AsynchronousOperation must implement the following methods.
Implement Real Behavior
Object realExecute(Map<String, Object> parameters);
Implements the real behavior of the deferred operation. Code with execution times that are too long to run as regular operations is processed with this method. Results are typically stored in a file for retrieval later on.
Get realExecute Results
Object getResult(IImmutableEntityTransaction transaction, Map<String, Object> parameters);
Gets the results produced by realExecute, typically by reading a file. After results are obtained, the method should call DeferredOperationsUtils.cleanupOperation to release resources used by the operation.
Get Operation Full Identifier
String getOperationFullIdentifier();
Returns the full identifier of an operation needed to call the operation asynchronously.
Clean Up Resources
void cleanUp(UUID operationUUID);
Cleans up resources reserved by an operation, and typically deletes the realExecute results file.
Full Example
package com.servicemax.core.asynchronous_operation
import java.util.Map
import com.intalio.core.data.api.IImmutableEntityTransaction;
import com.intalio.core.data.api.DeferredOperationUtils
class AsynchronousOperationExample extends AsynchronousOperation {
@Override
public Object realExecute(Map<String, Object> parameters) {
//emulates processing
sleep(1000 * 60);
//writes the result to a file
def file = new File(getFileName(parameters))
file.text = ''' This is the result'''
return null;
}
@Override
public Object getResult(IImmutableEntityTransaction transaction, Map<String, Object> parameters) {
//reads the result from the file written in realExecute
def file = new File(getFileName(parameters))
def lines = file.readLines()
//cleanup the result
DeferredOperationUtils.cleanupOperation(transaction, parameters);
return lines.join("\n")
}
@Override
public String getOperationFullIdentifier() {
return "io_asynchronous_operation_example";
}
private String getFileName(Map<String, Object> parameters) {
UUID operationUUID = DeferredOperationUtils.getOperationUUID(parameters)
getFileName(operationUUID)
}
private String getFileName(UUID operationUUID) {
"result_${operationUUID}"
}
}
Implementing Deferred Operation Without Results Checking
To execute operations asynchronously without results checking:
1. Create a regular operation to launch the deferred operation asynchronously, for example, my_launcher_operation.
◦ To launch another deferred or asynchronous operation, attach an event handler.
2. Create another regular operation to be called asynchronously, for example, my_deferred_operation_a, with a regular, simple execute method.
|
When this execute method runs, no transaction is attached to it, so be sure to create an execution environment inside which any record can be accessed.
|
3. In the my_launcher_operation method, call my_deferred_operation_a in the same manner as a deferred operation by using the currentTransaction.deferOperation utility.
Example
package com.servicemax.core.some_package
import com.servicemax.core;
\public class MyLauncherOperation {
@Override
public Object execute(Map<String, Object> parameters) {
\
//do something with the received parameters, add parameters,etc
def newParameters = processParameters(parameters);
// call another Operation asynchronously
Max.currentTransaction.deferOperation("my_deferred_operation_a",
newParameters, false, 0);
return "true";
}
@Override
public Map<String, Object> processParameters( Map<String, Object> parameters) {
//do something, add parameters, etc
return parameters;
}
}
Deferred Operation Exclusive Execution
To support use cases where deferred operations must execute exclusively within the system, without concurrent execution of the same deferred operation, in the relevant Operation record, select the Deferred Operation Exclusive Execution check box.
After you make this setting, execution attempts that occur while another instance of the same operation is running cause the operation to fail with OperationIsAlreadyRunningException.
For more information: