New in 0.16.0

v0.16.1

Playbook

Promises On Asynchronous Tasks

The code examples for pages in this section are available on Github.

You may want to execute remote tasks asynchronously while still being able to handle their errors or perform actions after their completion.

The simplest way to do this is to run the remote task within a child-workflow. It's even possible to do it within the same workflow. This is what we are going to illustrate here.

Let's consider a RemoteService with two foo and bar methods:

The @Name annotation is used by Infinitic for Workflow and Service identification.

For this example, our dummy implementation will be:

The AsyncMethodWorkflow that use this service has the following contract:

It has a main run method, and we added a remoteServiceFoo method with the same parameters than RemoteService::foo.

Here is an implementation:

The AsyncMethodWorkflowImpl class implements the AsyncMethodWorkflow interface and extends the Workflow class provided by Infinitic.

Let's examine its key parts:

  • The self property is a reference to the current workflow, allowing the workflow to dispatch methods to itself.

  • The remoteService property is a stub of RemoteService.

  • The run method is the main entry point of the workflow, it:

    • dispatches the remoteServiceFoo method asynchronously.
    • calls RemoteService.bar synchronously, with a log before and after
    • returns the output of the RemoteService.bar call.
  • The remoteServiceFoo method, which is asynchronously called:

    • calls RemoteService.bar synchronously, with a log before and after
    • and returns its result (but one is listening) as the call was asynchronous.

    At last, The log method is an utility method to log messages with a timestamp, workflow ID, and method ID. It used the Infinitic's inline() function ensuring proper handling of operations with side-effect.

To launch an instance :

A typical output (from the worker console):

04:33:52:087 - Workflow 0190d090-38fc-7dbb-a09f-90c497e24b93 - Dispatching 'bar(100)'
04:33:52:178 - Workflow 0190d090-38fc-7dbb-a09f-90c497e24b93 - Dispatching 'foo(1000)'
04:33:52:178 - Service  0190d090-3baa-7c35-9084-50a06044b868 - start processing 'bar(100)'
04:33:52:202 - Service  0190d090-3baa-7911-a4c3-af416a4ffc3c - start processing 'foo(1000)'
04:33:52:281 - Service  0190d090-3baa-7c35-9084-50a06044b868 - stop  processing 'bar(100)'
04:33:52:314 - Workflow 0190d090-38fc-7dbb-a09f-90c497e24b93 - Receiving: 'bar(100)' completed
04:33:53:208 - Service  0190d090-3baa-7911-a4c3-af416a4ffc3c - stop  processing 'foo(1000)'
04:33:53:243 - Workflow 0190d090-38fc-7dbb-a09f-90c497e24b93 - Receiving: 'foo(1000)' completed

As you can see, the run() methods returns before the end of the foo task.

The remoteServiceFoo could be updated to handle any error of the foo method, or simply to continue the execution with more tasks.

Previous
Building A Workflow Scheduler