cancel
Showing results for 
Search instead for 
Did you mean: 

Competing for tasks

ritchieannand
Champ in-the-making
Champ in-the-making
If you're writing something that uses the Activiti API to automatically handle something, but there could be multiple copies of it, is there a good way to have it work with the workflow and handle the inevitable collisions?

I was thinking about having the workflow split into a "queued" user/manual task and a "processing" user/manual task:

[ Queued ] —> [ Processing ] —>

And the automated process would do something like this:


boolean success = false;
while (!success)
{
    List<Task> queuedTasks = getProcessEngine().getTaskService().createTaskQuery().orderByDueDateNullsFirst().asc().taskId("queued").list();
    if (queuedTasks.size() > 0)
    {
        Task claimableTask = queuedTasks.get(0);
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("claimed", myProcessId); // There would be no other way to tell which task we claimed, would there?
        try
        {
            getProcessEngine().getTaskService().complete(claimableTask.getId(), variables);
            success = true;
        }
        catch (ActivitiObjectNotFoundException e)
        {
            // Something else claimed it? We'll try again.
        }
    }
    else
        break;
}


I prefer a "pull" model like this (hence the UserTask instead of a ServiceTask) in case it needs to get spun up on multiple VMs.

Will this cause problems? Are there better ways of accomplishing this?

Regards,

– Ritchie Annand
3 REPLIES 3

jbarrez
Star Contributor
Star Contributor
I'm not fully following here, why wouldn't you use an async service task for this? The job executor solves the competing already for you?

ritchieannand
Champ in-the-making
Champ in-the-making
Service tasks are outbound, right? You'd need to either be running multiple Activiti servers or put together something for a single Activiti server that can do a "round robin" technique of handing out the service task (or do the "round robin" from a bean), I take it.

Not that it's not possible, it's just that running the Activiti API from multiple machines and querying manual/user tasks is SO much easier than configuring servers to be registered and visible from something called by a JavaDelegate Smiley Happy

I did attempt 'Asynchronous' using an API client, but that really is Activiti-server-only; clients can't really see that "between the task and the sequence flow" state (at least not until the due date happens.

The code above works pretty nicely in my testing, but I haven't tried running multiple instances yet. I'm guessing there would be two major cases that Activiti's API might already handle:

* Optimistic locking failure trying to complete the task at the same time as someone else?
* Losing the battle when trying to complete the task because it's already been completed by someone else

It's fun starting processes manually and watching the agent grab them, do its work and then proceed or move to the failure state. I *really* like the "My instances" view in the Process section of Activiti Explorer. Nice red highlights showing where the tasks are now and where they've been. Sweet Smiley Happy

– Ritchie

jbarrez
Star Contributor
Star Contributor
Service tasks are not outbound, you write any logic you want in it. You also can use script tasks, no jar deployment needed.

The Job Executor of Activiti will do retries in case of failures. It also catches optimistic locking exceptions and assumes it has been picked up by another job executor.

Clients can indeed not see that state, but should they? Would you rather have them wait until the -possibly long- logic has been executed?