# Workflow timeout and saga compensation

**URL:** <https://community.temporal.io/t/workflow-timeout-and-saga-compensation/8377>\
**Category:** Community Support\
**Tags:** java-sdk\
**Created:** [May 29, 2023, 7:39am UTC](https://community.temporal.io/t/workflow-timeout-and-saga-compensation/8377 "2023-05-29T07:39:51Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![AndreaColombo](https://avatars.discourse-cdn.com/v4/letter/a/f475e1/32.png) [@AndreaColombo](https://community.temporal.io/u/AndreaColombo)\
**Post date:** [May 29, 2023, 7:39am UTC](https://community.temporal.io/t/workflow-timeout-and-saga-compensation/8377/1 "2023-05-29T07:39:51Z")

</div>

HI,  
I have a question related to workflow timeout and saga campnsation.

Let’s say I have a workflow which defines a saga object and registers several compensation activities (depending on code path).  
The workflow defines a workflow execution timeout.

Is there any way to have the compensation activities invoked even if the workflow timeout expires?  
Thanks

---

<div class="post-metadata">

**Author:** ![antonio.perez](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/antonio.perez/32/2417_2.png) [@antonio.perez](https://community.temporal.io/u/antonio.perez)\
**Post date:** [May 29, 2023, 9:30am UTC](https://community.temporal.io/t/workflow-timeout-and-saga-compensation/8377/2 "2023-05-29T09:30:46Z")

</div>

Hello @AndreaColombo

Workflow timeout is performed by the server and can not be handled in workflow code

You can use workflow timer to handle business-level timeouts.

```auto
      Saga saga = new Saga...;

      Workflow.newTimer(Duration.ofSeconds(3))
          .thenApply(
              result -> {
                saga.compensate();
                return result;
              });

```

---

<div class="post-metadata">

**Author:** ![AndreaColombo](https://avatars.discourse-cdn.com/v4/letter/a/f475e1/32.png) [@AndreaColombo](https://community.temporal.io/u/AndreaColombo)\
**Post date:** [May 29, 2023, 1:48pm UTC](https://community.temporal.io/t/workflow-timeout-and-saga-compensation/8377/3 "2023-05-29T13:48:27Z")

</div>

it makes sense.  
thanks for the prompt answer

---

<div class="post-metadata">

**Author:** ![AndreaColombo](https://avatars.discourse-cdn.com/v4/letter/a/f475e1/32.png) [@AndreaColombo](https://community.temporal.io/u/AndreaColombo)\
**Post date:** [May 29, 2023, 3:37pm UTC](https://community.temporal.io/t/workflow-timeout-and-saga-compensation/8377/4 "2023-05-29T15:37:16Z")

</div>

I have one more question, anyway.  
Is there any other way to trigger the compensation on workflow timeout without defining the timer within the workflow code? In a way that is “transparent” to the workflow implementation?  
Thanks  
A

---

<div class="post-metadata">

**Author:** ![antonio.perez](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/antonio.perez/32/2417_2.png) [@antonio.perez](https://community.temporal.io/u/antonio.perez)\
**Post date:** [May 29, 2023, 11:30pm UTC](https://community.temporal.io/t/workflow-timeout-and-saga-compensation/8377/5 "2023-05-29T23:30:39Z")

</div>

Hello @AndreaColombo

You can maybe try putting the logic in listeners instead of in workflow code, not sure if it will work I have not tested it.

But in the end, is still part of the workflow implementation.

---

<div class="post-metadata">

**Author:** ![maxim](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/maxim/32/8_2.png) [@maxim](https://community.temporal.io/u/maxim)\
**Post date:** [May 30, 2023, 3:39am UTC](https://community.temporal.io/t/workflow-timeout-and-saga-compensation/8377/6 "2023-05-30T03:39:36Z")

</div>

You can abstract this behavior in its own utility class or even interceptor.

---

<div class="post-metadata">

**Author:** ![Satirex\_S](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/satirex_s/32/4683_2.png) [@Satirex\_S](https://community.temporal.io/u/Satirex_S)\
**Post date:** [December 18, 2023, 1:43pm UTC](https://community.temporal.io/t/workflow-timeout-and-saga-compensation/8377/7 "2023-12-18T13:43:29Z")

</div>

Question to this solution - lets say I have a saga like this:

```auto
final Saga saga = new Saga(sagaOptions);
Workflow.newTimer(Duration.ofSeconds(3))
          .thenApply(
              result -> {
                saga.compensate();
                return result;
              });
try {
            activity1.doStuff();
            saga.addCompensation(activity1::compensate);
            activity2.doStuff();
}
catch(ActivityFailure cause) {
            saga.compensate();
            throw cause;
}

```

What happens, if the timeout happens after starting activity1.doStuff() and before reaching saga.addCompensation? Is workflow waiting for activity1 to finish execution before starting compensation? Even if so, following statement addCompensation won’t be executed and therefore compensation of activity1 won’t happen?  
It seems weird to add compensation first and then calling actual operation, especially if the compensation depends on the operation outcome.

---

<div class="post-metadata">

**Author:** ![maxim](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/maxim/32/8_2.png) [@maxim](https://community.temporal.io/u/maxim)\
**Post date:** [December 18, 2023, 7:24pm UTC](https://community.temporal.io/t/workflow-timeout-and-saga-compensation/8377/8 "2023-12-18T19:24:21Z")

</div>

You don’t want to call compensate on a timer in a separate thread. This would lead to a behavior in the main thread that is hard to understand. I would recommend calling cancellation using CancellationScope on the timeout.  
Something like:

```auto
    final Saga saga = new Saga(sagaOptions);
    
    CancellationScope cancellationScope = Workflow.newCancellationScope(()-> {
      try {
        activity1.doStuff();
        saga.addCompensation(activity1::compensate);
        activity2.doStuff();
      } catch (ActivityFailure cause) {
        saga.compensate();
        throw cause;
      }
    });
    Workflow.newTimer(Duration.ofSeconds(3))
            .thenApply(
                    result -> {
                      cancellationScope.cancel();
                      return null;
                    });

    cancellationScope.run();

  }

```

---

<div class="post-metadata">

**Author:** ![Satirex\_S](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/satirex_s/32/4683_2.png) [@Satirex\_S](https://community.temporal.io/u/Satirex_S)\
**Post date:** [December 19, 2023, 8:09am UTC](https://community.temporal.io/t/workflow-timeout-and-saga-compensation/8377/9 "2023-12-19T08:09:27Z")

</div>

Thank you for the quick response. So if I understand correctly with the CancellationScope, when the timeout is triggered, cancellation for the workflow is called and saga is then compensated within same thread as its execution.  
Does the thread upon cancellation wait for current activity execution to finish and also does it add the following compensation? Or is saga compensation executed immediately and therefore the last activity may not be compensated?

---

<div class="post-metadata">

**Author:** ![maxim](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/maxim/32/8_2.png) [@maxim](https://community.temporal.io/u/maxim)\
**Post date:** [December 19, 2023, 4:58pm UTC](https://community.temporal.io/t/workflow-timeout-and-saga-compensation/8377/10 "2023-12-19T16:58:55Z")

</div>

> Thank you for the quick response. So if I understand correctly with the CancellationScope, when the timeout is triggered, cancellation for the workflow is called and saga is then compensated within same thread as its execution.

The cancellation of the code in the cancellation scope is triggered, not the whole workflow. Each workflow runs in a _root_ cancellation scope which is canceled when the whole workflow is canceled.

> Does the thread upon cancellation wait for current activity execution to finish and also does it add the following compensation?

You can configure the behavior of an activity in case of compensation through ActivityOptions.cancellationType. You can decide to wait or send cancellation request and immediately return an exception. As activity fails with an exception then compensation is not going to be added. To handle this use case add compensation before calling an activity:

```auto
        saga.addCompensation(activity1::compensate);
        activity1.doStuff();

```

Note that in this case the `compensate` should account for cases that activity never started.

---

<div class="post-metadata">

**Author:** ![Satirex\_S](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/satirex_s/32/4683_2.png) [@Satirex\_S](https://community.temporal.io/u/Satirex_S)\
**Post date:** [December 20, 2023, 10:34am UTC](https://community.temporal.io/t/workflow-timeout-and-saga-compensation/8377/11 "2023-12-20T10:34:59Z")

</div>

ah, I was worried compensation needs to be done like this, which makes it much more difficult to implement. But now it seems clear, thank you very much.

---

<div class="post-metadata">

**Author:** ![gvlineate](https://sea2.discourse-cdn.com/flex016/user_avatar/community.temporal.io/gvlineate/32/4699_2.png) [@gvlineate](https://community.temporal.io/u/gvlineate)\
**Post date:** [December 26, 2023, 10:17am UTC](https://community.temporal.io/t/workflow-timeout-and-saga-compensation/8377/12 "2023-12-26T10:17:51Z")

</div>

Hi all

I tried to use this pattern - cancellationScope + Timer - to run compensations if a timeout fires for workflow and meet an unexpected behaviour:  
my compensation activity immediately fails because of CanceledFailure ::

Is it true cancel should trigger compensation and allow it to complete?

* * *

UPDATE:

Just found [another thread](https://community.temporal.io/t/saga-compensate-vs-workflow-cancellationscope/1297/2) in which you say we need to use DetachedCancellationScope to run compensations on cancelFailures.  
This fixed my issue.

Thank you
