Skip to content

Commit

Permalink
feat: add WithoutCancel (#200)
Browse files Browse the repository at this point in the history
* feat: add WithoutCancel

* fix: hound complaint

* fix: WithoutCancel should panic when parent is nil

* fix: tests

* fix: naked return is not good for readability

* chore: surpress linter

Co-authored-by: Trock <g_trock@163.com>
  • Loading branch information
Reasno and GGXXLL committed Sep 27, 2021
1 parent 9dac159 commit f905961
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 0 deletions.
43 changes: 43 additions & 0 deletions ctxmeta/without_cancel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package ctxmeta

import (
"context"
"time"
)

type asyncContext struct {
ctx context.Context
}

func (a asyncContext) Deadline() (deadline time.Time, ok bool) {
return time.Time{}, false
}

func (a asyncContext) Done() <-chan struct{} {
return nil
}

func (a asyncContext) Err() error {
return nil
}

func (a asyncContext) Value(key interface{}) interface{} {
return a.ctx.Value(key)
}

// WithoutCancel creates a new context from an existing context and inherits all
// values from the existing context. However if the existing context is
// cancelled, timeouts or passes deadline, the returning context will not be
// affected. This is useful in an async HTTP handler. When the http response is sent,
// the request context will be cancelled. If you still want to access the value from request context (eg. tracing),
// you can use:
// func(request *http.Request, responseWriter http.ResponseWriter) {
// go DoSomeSlowDatabaseOperation(WithoutCancel(request.Context()))
// responseWriter.Write([]byte("ok"))
// }
func WithoutCancel(requestScopeContext context.Context) (valueOnlyContext context.Context) {
if requestScopeContext == nil {
panic("cannot create context from nil parent")
}
return asyncContext{requestScopeContext}
}
33 changes: 33 additions & 0 deletions ctxmeta/without_cancel_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ctxmeta

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
)

func TestWithoutCancel(t *testing.T) {
key := struct{}{}
ctx := context.WithValue(context.Background(), key, "value")
ctx, cancel := context.WithCancel(ctx)
cancel()

select {
case <-WithoutCancel(ctx).Done():
t.Fatal("context is cancelled")
default:
}

_, dead := WithoutCancel(ctx).Deadline()
assert.False(t, dead)
assert.Nil(t, WithoutCancel(ctx).Err())
assert.Equal(t, "value", WithoutCancel(ctx).Value(key))
}

func TestWithoutCancel_Nil(t *testing.T) {
defer func() {
assert.Equal(t, "cannot create context from nil parent", recover())
}()
WithoutCancel(nil) //nolint
}

0 comments on commit f905961

Please sign in to comment.