Handling asynchronous methods' completion and results
Depending on the logic of the device management action, certain methods included in the action script may have to be executed in a strictly consecutive order. This is not a problem with synchronous methods, as they are always executed sequentially and the results from their execution are always available immediately as method return values. However, the confirmation of the execution of asynchronous methods and the reporting of their return values may not be available for quite a long time, and will definitely not be available as method result values as was the case with synchronous methods. This may lead to difficulties in the programming of the entire action script if another method's execution has to take this confirmation or result into account.
This problem is resolved through the special style of programming called Continuation Passing Style (CPS). Its main idea is to pass a function (a closure in Groovy terms) as a last argument that contains a logic defining how to continue the execution depending on the passed result. As defined in the official Groovy language documentation , a closure is an open, anonymous, block of code that can take arguments, return a value and be assigned to a variable. By specification, a Groovy closure can be placed anywhere in the code.
The mass management functionality of Bosch IoT Manager allows you to provide a closure to all Groovy DI API methods as an additional last argument. Such closures are executed only after the completion of the method in which this closure is a last argument.
When using the API method,
foo(arg1, arg2, arg3)
Method calls in groovy could be:
foo(arg1, arg2, arg3)
// or
// Closure postAction = { arg1, arg2 -> println "Command finished, args are: $arg1, $arg2" } foo(arg1, arg2, arg3, postAction)
If the foo method is asynchronous, the closure code will be run after the asynchronous execution has been completed, perhaps long after the script for the respective device has finished.
To ensure this, the system stores such closures in the database and restores them when confirmation of foo from the device is received. Even if this confirmation comes minutes, hours, or days after the task/rule execution on this device, the closure will remain in the database and will be run after the real asynchronous completion.
Such closures can also make use of the results of the asynchronous execution (see next section), and since they are kept in a database they will also survive a restart or a crash of the Suite service.
To summarize, Groovy closures are defined and applied in order to achieve sequential execution of asynchronous methods.