Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.

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

### Fixed

Expand Down
6 changes: 4 additions & 2 deletions connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -984,7 +984,8 @@ func (conn *Connection) newFuture(req Request) (fut *Future) {
if ctx != nil {
select {
case <-ctx.Done():
fut.SetError(fmt.Errorf("context is done (request ID %d)", fut.requestId))
fut.SetError(fmt.Errorf("context is done (request ID %d): %w",
fut.requestId, context.Cause(ctx)))
shard.rmut.Unlock()
return
default:
Expand Down Expand Up @@ -1026,7 +1027,8 @@ func (conn *Connection) contextWatchdog(fut *Future, ctx context.Context) {
case <-fut.done:
return
default:
conn.cancelFuture(fut, fmt.Errorf("context is done (request ID %d)", fut.requestId))
conn.cancelFuture(fut, fmt.Errorf("context is done (request ID %d): %w",
fut.requestId, context.Cause(ctx)))
}
}

Expand Down
2 changes: 1 addition & 1 deletion example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func ExamplePingRequest_Context() {
fmt.Println("Ping Error", regexp.MustCompile("[0-9]+").ReplaceAllString(err.Error(), "N"))
// Output:
// Ping Resp data []
// Ping Error context is done (request ID N)
// Ping Error context is done (request ID N): context deadline exceeded
}

func ExampleSelectRequest() {
Expand Down
43 changes: 42 additions & 1 deletion tarantool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package tarantool_test
import (
"context"
"encoding/binary"
"errors"
"fmt"
"io"
"log"
Expand Down Expand Up @@ -48,7 +49,8 @@ type Member struct {
Val uint
}

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

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

// Checking comparable with simple context.WithCancel.
func TestComparableErrorsCanceledContext(t *testing.T) {
conn := test_helpers.ConnectWithValidation(t, dialer, opts)
defer conn.Close()

ctx, cancel := context.WithCancel(context.Background())
req := NewPingRequest().Context(ctx)
cancel()
_, err := conn.Do(req).Get()
require.True(t, errors.Is(err, context.Canceled), err.Error())
}

// Checking comparable with simple context.WithTimeout.
func TestComparableErrorsTimeoutContext(t *testing.T) {
conn := test_helpers.ConnectWithValidation(t, dialer, opts)
defer conn.Close()

timeout := time.Nanosecond
ctx, cancel := context.WithTimeout(context.Background(), timeout)
req := NewPingRequest().Context(ctx)
defer cancel()
_, err := conn.Do(req).Get()
require.True(t, errors.Is(err, context.DeadlineExceeded), err.Error())
}

// Checking comparable with context.WithCancelCause.
// Shows ability to compare with custom errors (also with ClientError).
func TestComparableErrorsCancelCauseContext(t *testing.T) {
conn := test_helpers.ConnectWithValidation(t, dialer, opts)
defer conn.Close()

ctxCause, cancelCause := context.WithCancelCause(context.Background())
req := NewPingRequest().Context(ctxCause)
cancelCause(ClientError{ErrConnectionClosed, "something went wrong"})
_, err := conn.Do(req).Get()
var tmpErr ClientError
require.True(t, errors.As(err, &tmpErr), tmpErr.Error())
}

// waitCtxRequest waits for the WaitGroup in Body() call and returns
// the context from Ctx() call. The request helps us to make sure that
// the context's cancel() call is called before a response received.
Expand Down
Loading