Skip to content

Commit 35dd810

Browse files
committed
connection: returing ctx.Cause error in canceled case
Returing wrapped context.Cause(ctx) error in <-ctx.Done() case. Allows compare errors using errors.Is/As. Add 3 tests errors checking comparabily. Fixes #457
1 parent cbcf6a4 commit 35dd810

File tree

4 files changed

+49
-4
lines changed

4 files changed

+49
-4
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.
1717

1818
* Required Go version is `1.24` now (#456).
1919
* `box.New` returns an error instead of panic (#448).
20+
* Now cases of `<-ctx.Done()` returns wrapped error provided by `ctx.Cause()`.
21+
Allows you compare it using `errors.Is/As` (#457).
2022

2123
### Fixed
2224

connection.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,8 @@ func (conn *Connection) newFuture(req Request) (fut *Future) {
984984
if ctx != nil {
985985
select {
986986
case <-ctx.Done():
987-
fut.SetError(fmt.Errorf("context is done (request ID %d)", fut.requestId))
987+
fut.SetError(fmt.Errorf("context is done (request ID %d): %w",
988+
fut.requestId, context.Cause(ctx)))
988989
shard.rmut.Unlock()
989990
return
990991
default:
@@ -1026,7 +1027,8 @@ func (conn *Connection) contextWatchdog(fut *Future, ctx context.Context) {
10261027
case <-fut.done:
10271028
return
10281029
default:
1029-
conn.cancelFuture(fut, fmt.Errorf("context is done (request ID %d)", fut.requestId))
1030+
conn.cancelFuture(fut, fmt.Errorf("context is done (request ID %d): %w",
1031+
fut.requestId, context.Cause(ctx)))
10301032
}
10311033
}
10321034

example_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ func ExamplePingRequest_Context() {
167167
fmt.Println("Ping Error", regexp.MustCompile("[0-9]+").ReplaceAllString(err.Error(), "N"))
168168
// Output:
169169
// Ping Resp data []
170-
// Ping Error context is done (request ID N)
170+
// Ping Error context is done (request ID N): context deadline exceeded
171171
}
172172

173173
func ExampleSelectRequest() {

tarantool_test.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package tarantool_test
33
import (
44
"context"
55
"encoding/binary"
6+
"errors"
67
"fmt"
78
"io"
89
"log"
@@ -48,7 +49,8 @@ type Member struct {
4849
Val uint
4950
}
5051

51-
var contextDoneErrRegexp = regexp.MustCompile(`^context is done \(request ID [0-9]+\)$`)
52+
var contextDoneErrRegexp = regexp.MustCompile(
53+
`^context is done \(request ID [0-9]+\): context canceled$`)
5254

5355
func (m *Member) EncodeMsgpack(e *msgpack.Encoder) error {
5456
if err := e.EncodeArrayLen(2); err != nil {
@@ -2742,6 +2744,45 @@ func TestClientRequestObjectsWithPassedCanceledContext(t *testing.T) {
27422744
}
27432745
}
27442746

2747+
// Checking comparable with simple context.WithCancel.
2748+
func TestComparableErrorsCanceledContext(t *testing.T) {
2749+
conn := test_helpers.ConnectWithValidation(t, dialer, opts)
2750+
defer conn.Close()
2751+
2752+
ctx, cancel := context.WithCancel(context.Background())
2753+
req := NewPingRequest().Context(ctx)
2754+
cancel()
2755+
_, err := conn.Do(req).Get()
2756+
require.True(t, errors.Is(err, context.Canceled), err.Error())
2757+
}
2758+
2759+
// Checking comparable with simple context.WithTimeout.
2760+
func TestComparableErrorsTimeoutContext(t *testing.T) {
2761+
conn := test_helpers.ConnectWithValidation(t, dialer, opts)
2762+
defer conn.Close()
2763+
2764+
timeout := time.Nanosecond
2765+
ctx, cancel := context.WithTimeout(context.Background(), timeout)
2766+
req := NewPingRequest().Context(ctx)
2767+
defer cancel()
2768+
_, err := conn.Do(req).Get()
2769+
require.True(t, errors.Is(err, context.DeadlineExceeded), err.Error())
2770+
}
2771+
2772+
// Checking comparable with context.WithCancelCause.
2773+
// Shows ability to compare with custom errors (also with ClientError).
2774+
func TestComparableErrorsCancelCauseContext(t *testing.T) {
2775+
conn := test_helpers.ConnectWithValidation(t, dialer, opts)
2776+
defer conn.Close()
2777+
2778+
ctxCause, cancelCause := context.WithCancelCause(context.Background())
2779+
req := NewPingRequest().Context(ctxCause)
2780+
cancelCause(ClientError{ErrConnectionClosed, "something went wrong"})
2781+
_, err := conn.Do(req).Get()
2782+
var tmpErr ClientError
2783+
require.True(t, errors.As(err, &tmpErr), tmpErr.Error())
2784+
}
2785+
27452786
// waitCtxRequest waits for the WaitGroup in Body() call and returns
27462787
// the context from Ctx() call. The request helps us to make sure that
27472788
// the context's cancel() call is called before a response received.

0 commit comments

Comments
 (0)