Using NewDetachedCancellationScope for non-cancellation scenarios

Hi Temporal team,

I’m trying to simplify some Workflow code with regards to cleanup logic:

try {

// run some activities

} catch (ActivityFailure e) {
// error handling
}
catch (CanceledFailure e) {

// run activity to cleanup a record in DB, using NewDetachedCancellationScope

} finally {

// run activity to cleanup a record in DB

}

Basically, I want to run an activity to cleanup a record in DB, whether there was an Activity failure, or if Workflow was canceled, or Workflow completed successfully. This is done in finally.
Is there any drawback to using NewDetachedCancellationScope in the finally clause?

thanks,
Richard

Activity invocations through activity stub throw only ActivityFailure exception. So In case of wf cancellation that happens during activity execution, you will catch ActivityFailure which will have CanceledFailure as its cause. So imo you dont need to catch both ActivityFailure and CanceledFailure failures separately, but for example just catch ActivityFailure e and you can check if its CanceledFailure if you need:

if(e.getCause() instanceof CanceledFailure) {
            // do some cancellation cleanup here
        }

Think it’s ok to have newDetachedCancellationScope in finally. In case where you want to do the cleanup only on activity failure or cancellation request, you should be able to handle that by catching ActivityFailure alone ( see sample: samples-java/HelloDetachedCancellationScope.java at main · temporalio/samples-java · GitHub)

Thanks!

In the case of cancel on WorkflowStub, a CanceledFailure would be thrown. So we would still need a separate catch block right?

For your example code you can just catch TemporalFailure which is going to be either ActivityFailure (with the CanceledFailure as cause) or CanceledFailure. If it’s ActivityFailure you can perform some compensation logic if needed for the activities (all in detached scope)

...
} catch (TemporalFailure e) {
   if (e instanceof ActivityFailure) {
      Workflow.newDetachedCancellationScope(() -> ...).run();
  } else if(e instanceof CanceledFailure) {
    Workflow.newDetachedCancellationScope(() -> ...).run();
  } 
 throw e;
}

you can also run your cleanup code in finally block as well if needed for your case.

1 Like

Thanks!

...
int foo;

...

} catch (TemporalFailure e) {
   if (e instanceof ActivityFailure) {
      Workflow.newDetachedCancellationScope(() -> ...).run();
  } else if(e instanceof CanceledFailure) {
    Workflow.newDetachedCancellationScope(() -> foo++).run();
  } 
 throw e;
}

Is this allowed? Even though foo is declared in root scope which was canceled?

Yes, see detached cencellation scope sample.