Skip to content

Commit 28724e2

Browse files
committed
⚙️ [parallelisation] Report the context cancellation cause in the related error to provide more context
1 parent 79919d4 commit 28724e2

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

changes/20251015114355.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:gear: `[parallelisation]` Report the context cancellation cause in the related error to provide more context

utils/parallelisation/contextual.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ import (
88

99
// DetermineContextError determines what the context error is if any.
1010
func DetermineContextError(ctx context.Context) error {
11-
return commonerrors.ConvertContextError(ctx.Err())
11+
err := commonerrors.ConvertContextError(ctx.Err())
12+
if commonerrors.Any(err, nil) {
13+
return err
14+
}
15+
return commonerrors.WrapError(err, context.Cause(ctx), "")
1216
}
1317

1418
type ContextualFunc func(ctx context.Context) error

utils/parallelisation/contextual_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ package parallelisation
22

33
import (
44
"context"
5+
"errors"
56
"testing"
7+
"time"
68

9+
"github.com/stretchr/testify/assert"
710
"github.com/stretchr/testify/require"
811

912
"github.com/ARM-software/golang-utils/utils/commonerrors"
@@ -49,3 +52,37 @@ func TestForEach(t *testing.T) {
4952
require.NoError(t, ForEach(context.Background(), WithOptions(Workers(5), JoinErrors), WrapCancelToContextualFunc(cancelFunc), WrapCancelToContextualFunc(cancelFunc), WrapCancelToContextualFunc(cancelFunc)))
5053
})
5154
}
55+
56+
func TestDetermineContextError(t *testing.T) {
57+
t.Run("normal", func(t *testing.T) {
58+
require.NoError(t, DetermineContextError(context.Background()))
59+
})
60+
t.Run("cancellation", func(t *testing.T) {
61+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
62+
defer cancel()
63+
require.NoError(t, DetermineContextError(ctx))
64+
cancel()
65+
err := DetermineContextError(ctx)
66+
errortest.AssertError(t, err, commonerrors.ErrTimeout, commonerrors.ErrCancelled)
67+
})
68+
t.Run("cancellation with cause", func(t *testing.T) {
69+
cause := errors.New("a cause")
70+
ctx, cancel := context.WithCancelCause(context.Background())
71+
defer cancel(cause)
72+
require.NoError(t, DetermineContextError(ctx))
73+
cancel(cause)
74+
err := DetermineContextError(ctx)
75+
errortest.AssertError(t, err, commonerrors.ErrTimeout, commonerrors.ErrCancelled)
76+
errortest.AssertErrorDescription(t, err, cause.Error())
77+
})
78+
t.Run("cancellation with timeout cause", func(t *testing.T) {
79+
cause := errors.New("a cause")
80+
ctx, cancel := context.WithTimeoutCause(context.Background(), 5*time.Second, cause)
81+
defer cancel()
82+
require.NoError(t, DetermineContextError(ctx))
83+
cancel()
84+
err := DetermineContextError(ctx)
85+
errortest.RequireError(t, err, commonerrors.ErrTimeout, commonerrors.ErrCancelled)
86+
assert.NotContains(t, err.Error(), cause.Error()) // the timeout did not take effect and a cancellation was performed instead so the cause is not passed through
87+
})
88+
}

0 commit comments

Comments
 (0)