cancel
Showing results for 
Search instead for 
Did you mean: 

Pushing available tasks to a custom UI - what Activity Event(s) to hook into?

jwestra
Champ in-the-making
Champ in-the-making
Hi!

I have a custom UI that has a Task Queue (available for claim) and I'm using Web Sockets to push data from the Server to each browser.  The solution I'd like to create is as follows:

1. Each time a new task is available for a set of candidates (whether it is an adhoc Task or a UserTask within a Process Instance flow), I'd like to push it to each browser UI Task Queue without a browser refresh.
2. Each time a task is take OFF a Task Queue by another user, push this info to all the other User's Task Queues so they no longer have the item to try and claim.

I've reviewed the list of events in the UserGuide, but I do not have a clear understanding of which ones to use.

Maybe "TASK_ASSIGNED" is all I need for the removal of the queue.  Thoughts on when to add new, available ones to the UI Task Queue?
7 REPLIES 7

jbarrez
Star Contributor
Star Contributor
the TASK_ASSIGNED would be the one for removing it of the group queue.
I think that you'll need a lowlevel entity_created event (and check if its a TaskEntity) to know that the task is there.

jwestra
Champ in-the-making
Champ in-the-making
Yes, I was trying to decide between ENTITY_CREATED and TASK_CREATED events.

If I do the low-level ENTITY_CREATED event, I fear there a chance that some information is set up yet that would cause the "claim" of it to fail or possibly not be able to load identity links for candidates.  Is that true? 

Perhaps, TASK_CREATED is published only after all these things are related, but I don't know.

jbarrez
Star Contributor
Star Contributor
Yes, the created event would have more data populated (like assignee)… the entity created event is low-lever and would come quicker.

jwestra
Champ in-the-making
Champ in-the-making
It looks like TASK_CREATED does not do what I want either, at least not completely (refer to original post)…

Here is what my code does:

I store candidate groups along with the Task in the same transaction and I listen for the TASK_CREATED event.

<code>
@Transactional
public Task saveTask(Task newTask) {
          taskService.saveTasK(newTask);
          taskService.addCandidateGroup(newTask.getId(), "someGroup");
          return newTask;
}

//Spring @Transaction commit;
</code>

TASK_CREATED listener looks like this:

<code>
public void onEvent(ActivitiEvent event) {
     ActivitiEntityEvent entityEvent = (ActivitiEntityEvent) event;
     Task taskEntity = (Task) entityEvent.getEntity();
     List<IdentityLink> identityLinkList = taskService
    .getIdentityLinksForTask(taskId);

// Get IdentityLink's that are type CANDIDATE and
// Broadcast using WebSockets to the browsers to tell each "candidate's" Queue there is a new task available for them to claim
}
</code>

However, the identityLinkList is empty inside the ActivitiEventListener, so I do not have the information I need to broadcast to the candidate browsers at this time.

It appears that the ActivitiEntityEvent TASK_CREATED is received before the transaction commit and if I look for candidates in that event listener, I see none.  Activiti must be using READ_COMMITTED on the call to TaskService.getIdentityLinksForTask(taskId), hence, it does not see that I wanted a candidate group for it.  Yes, still, I would've hoped a query inside the same transaction would read back the data.  This is using the H2 DataSource, BTW.  Would behavior be different on PostgreSQL?

It would be great if the TASK_CREATED was not raised until after Txn Commit.  Then, ActivitiEventListeners that receive the event can ask questions about it and get the answers consistent with the Txn & DB regardless of Driver & Database.

If there is another way to accomplish my goals that I am not seeing, please let me know.


jbarrez
Star Contributor
Star Contributor
The database does not matter. Activiti flushes at the _end_ of the transaction, hence why the call TaskService.getIdentityLinksForTask(taskId) does not give you the results.

One option you could look into is postponing the firing of your event after the transaction has been committed. The CommandContextCloseListener allows you do that. It would mean you have to 'collect' the data/callbacks you want to execute until after the transaction has been committed (the commandContext class has a 'attributes' member to store such information).

jwestra
Champ in-the-making
Champ in-the-making
Thank Joram.  I just to a look at that class and it appears to have an "impl" in the package, so I am hesitant about hooking in that deep. 

I guess will opt to postpone my logic until after the transaction commit by hooking into Spring's TransactionSynchronizationManager and wait for TransactionSynchronization.afterCommit() to handle things. 

That said, it would be sweet if Activiti handled event firing like that in the future, especially given it's tight coupling to Spring anyway Smiley Happy

jbarrez
Star Contributor
Star Contributor
Yes, it's a planned feature (for the v6) to add that as a first class method.