External Task Action Listeners?

Is there plans to add listeners for external tasks? and/or a way to implement this through another listener?
@thorben

Changes like:

  1. Lock
  2. Unlock
  3. Priority change
  4. Retries change
  5. Failures
2 Likes

Hi Stephen,

There are currently no such plans and I can’t think of a workaround to achieve this.

Cheers,
Thorben

@thorben checking in on this. Has there been any discussion about adding this capability?

I was thinking that could likely handle this using a cmd/db event listener through Context. Generate a Plugin that injects a global transaction listener that looks for the entities that are updating a external task.

Example usage here would be: Long running External tasks, send out a notification when a task is Fetched/Locked/Started

1 Like

Hi Stephen,

We still do not have plans for this.

Cheers,
Thorben

I understand there is not change in this area?
I was looking for a way to intercept event when external task is taken over because it exceeded lock time.

I have found that usually can work through these issues with Command Interceptors / CommandInterceptor.

Hello Team (@thorben and @StephenOTT )

Such a great post, thank you in advance for your proper reply.

We have found the post according to our requirement.
As you have described, we developed most important listener for external task services.

we have developed SetVariable method for external task some days ago and we could contribute on your project hopefully.

Its included below methods :slight_smile:

    public void onFetchAndLock(List<TopicRequestDto> topics);
    public void fetchAndLockDone(List<TopicRequestDto> topics, List<ExternalTask> externalTasks);
    public void fetchAndLockFail(List<TopicRequestDto> topics, EngineClientException e);

    public void onUnlock(String taskId);
    public void unlockDone(String taskId);
    public void unlockFail(String taskId, EngineClientException e);

    public void onSetVariable(String processInstanceId, VariableMap variables);
    public void setVariableDone(String processInstanceId, VariableMap variables);
    public void setvariableFail(String processInstanceId, VariableMap variables, EngineClientException e);

    public void onComplete(String taskId, Map<String, Object> variables, Map<String, Object> localVariables);
    public void completeDone(String taskId, Map<String, Object> variables, Map<String, Object> localVariables);
    public void completeFail(String taskId, Map<String, Object> variables, Map<String, Object> localVariables, EngineClientException e);

    public void onFailure(String taskId, String errorMessage, String errorDetails, int retries, long retryTimeout);
    public void failureDone(String taskId, String errorMessage, String errorDetails, int retries, long retryTimeout);
    public void failureFail(String taskId, String errorMessage, String errorDetails, int retries, long retryTimeout, EngineClientException e);

    public void onBpmnError(String taskId, String errorCode, String errorMessage, Map<String, Object> variables);
    public void bpmnErrorDone(String taskId, String errorCode, String errorMessage, Map<String, Object> variables);
    public void bpmnErrorFail(String taskId, String errorCode, String errorMessage, Map<String, Object> variables, EngineClientException e);

    public void onExtendLock(String taskId, long newDuration);
    public void extendLockDone(String taskId, long newDuration);
    public void extendLockFail(String taskId, long newDuration, EngineClientException e);

we have other methods for some customized services too.
Its our pleasure if we could share them with you and contribute on your developing.

Let me know your feedback.

Best Regards,
Taha Arian

3 Likes

@tahaarian If you have a sample project to check out some initial code that would be great to see

Hello again @StephenOTT

Yes, we have. it’s according to below source codes.

We have prepared a package for listeners and make the main interface ExternalTaskClientListener.java

ExternalTaskClientListener.txt (4.8 KB)

Then we developed the main class (DefaultExternalTaskClientListener) that was implemented follow the interface.

DefaultExternalTaskClientListener.txt (6.1 KB)

We could check the new API (setVariable) that we developed in class ExternalTaskServiceImpl.java

  @Override
  public void setVariables(String processInstanceId, VariableMap variables) {
    try {
      externalTaskClientListener.onSetVariable(processInstanceId,variables);
      engineClient.setVariables(processInstanceId, variables,getXsrf());
      externalTaskClientListener.setVariableDone(processInstanceId,variables);
    } catch (EngineClientException e) {
      externalTaskClientListener.setVariableFail(processInstanceId,variables,e);
      throw LOG.externalTaskServiceException("setting variables for external task", e);
    }
  }

As you could see, we have used three method listeners (onSetVariable,setVariableDone,setVariableFail)

In the end, we have a tester for the api as below source code :slight_smile:

        ExponentialBackoffStrategy backoffStrategy = new ExponentialBackoffStrategy(1000, 1, 1000);

        ExternalTaskClient taskClient = ExternalTaskClient.create()
                .addInterceptor(new CookieAuthProvider())
                .asyncResponseTimeout(2000)
                .backoffStrategy(backoffStrategy)
                .maxTasks(1)
                .externalTaskClientListener(new DefaultExternalTaskClientListener() {

                    @Override
                    public void unAuthorizedException(EngineClientException e) {
                        System.out.println("state: unAuthorizedException");
                        states.add("unAuthorizedException");
                    }

                    @Override
                    public void onFetchAndLock(List<TopicRequestDto> topics) {
                        System.out.println("state: onFetchAndLock");
                        states.add("onFetchAndLock");
                    }

                    @Override
                    public void fetchAndLockDone(List<TopicRequestDto> topics, List<ExternalTask> externalTasks) {
                        System.out.println("state: fetchAndLockDone");
                        states.add("fetchAndLockDone");
                    }

                    @Override
                    public void fetchAndLockFail(List<TopicRequestDto> topics, EngineClientException e) {
                        System.out.println("state: fetchAndLockFail");
                        states.add("fetchAndLockFail");
                    }

                    @Override
                    public void onSetVariable(String processInstanceId, VariableMap variables) {
                        System.out.println("state: onSetVariable");
                        states.add("onSetVariable");
                    }

                    @Override
                    public void setVariableDone(String processInstanceId, VariableMap variables) {
                        System.out.println("state: setVariableDone");
                        states.add("setVariableDone");
                    }

                    @Override
                    public void setVariableFail(String processInstanceId, VariableMap variables, EngineClientException e) {
                        System.out.println("state: setvariableFail");
                        states.add("setvariableFail");
                    }

                })
                .baseUrl(host + baseUrl)
                .build();

Its our pleasure if we could contribute in listener source code too.
Let me know your feedback

Thank you in advance

Taha Arian

1 Like

@tahaarian Nice work. Thanks for sharing :slight_smile:

Hello @aravindhrs

Your welcome.
We could contribute and make a pull request if you(@tasso94 nd @jonathan.lukas )prefer to update them.

Thank you in advance
Taha Arian

When the process engine encounters a service task that is configured to be externally handled, it creates an external task instance and adds it to a list of external tasks (step 1). The task instance receives a topic that identifies the nature of the work to be performed. At a time in the future, an external worker may fetch and lock tasks for a specific set of topics (step 2). To prevent one task being fetched by multiple workers at the same time, a task has a timestamp-based lock that is set when the task is acquired. Only when the l bpm counter ock expires, another worker can fetch the task again. When an external worker has completed the desired work, it can signal the process engine to continue process execution after the service task

1 Like