It is simpler, but it doesn’t work because the activity task can be lost before the approval was sent to an external system. So it will take 2 days for it to be timed out.
So using activity + signal/update is the way to go.
Hi! Thank you for your answers. Modeling human tasks is very important and as a new user I find it tricky to understand how to do it correctly in Temporal. Here are some of my thoughts so far:
In my approach I was not thinking about sending the approval request but just use temporal API to check for workflow activities pending (like temporal workflow describe). Then I don’t have to have a separate system, just “in-temporal” approvals.
The WaitForApproval task does not do anything in code, just waits. It’s return type describes what user input form must provide back.
You are right that if I wanted to have 2 tasks - RequestForApproval and WaitForApproval i don’t have a way to pass required activityId or TaskToken
In my approach the workflow status explicitly shows what the workflow is waiting for, right away in the UI. Operations team can quickly answer “Where is the process stuck?”
When considering the await + signal approach here are the drawbacks I see:
For developers coming from BPM (Camunda, Flowable) or other tools (Kestra, Conductor), it is natural way that human activities are modeled as tasks/activities. They’ll look for HumanTask or something similar. Modelling as timer + flag + update function.
The fact that Workflow.await timer is not completed when the condition is met and developer needs to wrap it into cancellation scope makes it quite complex.
Some state/data “leaks” into the workflow code. I need to have a property to update in Signal and then something checks it. Looks like synchronization flags. Maybe I could just complete some Promise instead somehow in the signal function?
The UI shows that the process is stuck on timer, or few timers. There are no pending activities, just timer.
@antonio.perez I’m looking into the sample from the PR and I see that this is super complex, hiding the complexity as sub-workflows but the WorkflowWithTasksImpl looks quite nice. I need to run it to see how it looks like in UI for troubleshooting.
In my approach I was not thinking about sending the approval request but just use temporal API to check for workflow activities pending (like temporal workflow describe). Then I don’t have to have a separate system, just “in-temporal” approvals.
This can be very inefficient if you have many workflows with pending activities. How the system knows how many pending tasks the user X has?
In my approach the workflow status explicitly shows what the workflow is waiting for, right away in the UI. Operations team can quickly answer “Where is the process stuck?”
I think you should use queries to check the internal state
For developers coming from BPM (Camunda, Flowable) or other tools (Kestra, Conductor), it is natural way that human activities are modeled as tasks/activities. They’ll look for HumanTask or something similar. Modelling as timer + flag + update function.
nothing stops you from creating your customs wrappers, similar to how it is done on the example I shared.
The fact that Workflow.await timer is not completed when the condition is met and developer needs to wrap it into cancellation scope makes it quite complex.
please refer to my previous comment
Some state/data “leaks” into the workflow code. I need to have a property to update in Signal and then something checks it. Looks like synchronization flags. Maybe I could just complete some Promise instead somehow in the signal function?
I am unsure why this is wrong, but same.. “taskService” helper class or something similar can help with this.
The UI shows that the process is stuck on timer, or few timers. There are no pending activities, just timer.
If that is the issue you could create a child workflow with the activity+signal implementation. To me, this feels like overkill, but it would work the same way.
Thank you. I am trying to implement this using signal approach. This is my code for 3 approvals. It is quite complex and still timeout is not there (I know I need cancellation scope for this)
private final Map<String, Promise<Approval>> approvals = new HashMap<>();
@Override
public void startOnboarding(OnboaringData onboaringData) {
activityStub.recordNewClient(onboaringData);
logger.info("Waiting for approval");
requestForApproval();
requestForApproval();
requestForApproval();
var allApprovals = Promise.allOf(this.approvals.values());
Workflow.await(() -> allApprovals.isCompleted()); // <-- Is this line needed?
allApprovals.get();
String msg = "";
for (Promise<Approval> valPromise : this.approvals.values()) {
msg += valPromise.get().message() + " , ";
}
logger.info("Got all approvals {}", msg);
}
private void requestForApproval() {
var taskId = Workflow.randomUUID().toString();
activityStub.requestForApproval(taskId);
CompletablePromise<Approval> promise = Workflow.newPromise();
this.approvals.put(taskId, promise);
}
@Override
public void approve(String taskId, String message) {
var promise = (CompletablePromise<Approval>) this.approvals.get(taskId);
promise.complete(new Approval(message, Status.APPROVED));
}
@Override
public String getWaitingStep() {
String res = "";
for (Entry<String, Promise<Approval>> e : this.approvals.entrySet()) {
if (!((CompletablePromise<Approval>) e.getValue()).isCompleted()) {
res += e.getKey() + ",";
}
}
return res;
}