Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

增加上下文时限管理能力 #54

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
9 changes: 9 additions & 0 deletions util/gopool/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package gopool

import (
"context"
"github.com/bytedance/gopkg/util/hcontext"
"runtime"
"sync"
"sync/atomic"
Expand All @@ -30,6 +31,8 @@ type Pool interface {
Go(f func())
// CtxGo executes f and accepts the context.
CtxGo(ctx context.Context, f func())
// CtxGoNoDeadlineOrCancel executes f and will be no timeouts and cancellations
CtxGoNoDeadlineOrCancel(ctx context.Context,f func())
// SetPanicHandler sets the panic handler.
SetPanicHandler(f func(context.Context, interface{}))
}
Expand Down Expand Up @@ -138,6 +141,12 @@ func (p *pool) CtxGo(ctx context.Context, f func()) {
}
}

func (p *pool) CtxGoNoDeadlineOrCancel(ctx context.Context,f func()) {
ctx = hcontext.WithNoCancel(ctx)
ctx = hcontext.WithNoDeadline(ctx)
CtxGo(ctx,f)
}

// SetPanicHandler the func here will be called after the panic has been recovered.
func (p *pool) SetPanicHandler(f func(context.Context, interface{})) {
p.panicHandler = f
Expand Down
15 changes: 15 additions & 0 deletions util/hcontext/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# hcontext
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感觉像是对标准库 context 的增强,不如放在 lang 下,取名为 contextx?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


## 功能

对 context.Context 的包装函数

## usage

```golang
//移除超时信息,保留value信息
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在 // 后加一个空格,并且 README.md 改为英文吧,中文的可以放在 README_ZH.md 中,同时记得英文和中文间加个空格,如下:

// 移除超时信息,保留 value 信息

下同。

ctx = hcontext.WithNoDeadline(ctx)

//移除取消信息,保留超时和value信息
ctx = hcontext.WithNoCancel(ctx)
```
30 changes: 30 additions & 0 deletions util/hcontext/hcontext.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package hcontext

import (
"context"
"time"
)

type valueOnlyContext struct{ context.Context }

func (valueOnlyContext) Deadline() (deadline time.Time, ok bool) { return }
func (valueOnlyContext) Done() <-chan struct{} { return nil }
func (valueOnlyContext) Err() error { return nil }

//WithNoDeadline 移除超时控制,保留value信息
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment 改成英文吧,记得 // 后加空格,下同。

func WithNoDeadline(ctx context.Context) context.Context {
return valueOnlyContext{ctx}
}

//WithNoCancel 不受上层context cancel的影响,但是保留上层ctx的Deadline信息
func WithNoCancel(ctx context.Context) context.Context {
deadline, ok := ctx.Deadline()
if ok {
var cancel context.CancelFunc
ctx = WithNoDeadline(ctx)
ctx, cancel = context.WithDeadline(ctx, deadline)
_ = cancel
return ctx
}
return WithNoDeadline(ctx)
}
152 changes: 152 additions & 0 deletions util/hcontext/hcontext_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package hcontext

import (
"context"
"testing"
"time"

"gopkg.in/go-playground/assert.v1"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

用 testify 吧,不引入新的依赖了

)

type ctxtype string

var k ctxtype = "k"

func TestWithNoDeadline(t *testing.T) {
type args struct {
ctx context.Context
}
tests := []struct {
name string
args args
stub func(*testing.T, context.Context)
}{
{
name: "value正常传递",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

改为英文吧,下同

args: args{
context.WithValue(context.TODO(), k, "world"),
},
stub: func(t *testing.T, ctx context.Context) {
assert.Equal(t, ctx.Value(k).(string), "world")
},
},
{
name: "nil Deadline()",
args: args{
ctx: func() context.Context {
ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
_ = cancel
return ctx
}(),
},
stub: func(t *testing.T, ctx context.Context) {
deadline, ok := ctx.Deadline()
assert.Equal(t, deadline.IsZero(), true)
assert.Equal(t, ok, false)

},
},
{
name: "nil Done()",
args: args{
ctx: func() context.Context {
ctx, cancel := context.WithTimeout(context.TODO(), time.Microsecond)
_ = cancel
return ctx
}(),
},
stub: func(t *testing.T, ctx context.Context) {
assert.Equal(t, ctx.Done(), nil)
},
},
{
name: "nil Err()",
args: args{
ctx: func() context.Context {
ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
cancel()
return ctx
}(),
},
stub: func(t *testing.T, ctx context.Context) {
assert.Equal(t, ctx.Err(), nil)
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := WithNoDeadline(tt.args.ctx)
tt.stub(t, got)
})
}
}

func TestWithNoCancel(t *testing.T) {
type args struct {
ctx context.Context
}
tests := []struct {
name string
args args
stub func(*testing.T, context.Context)
}{
{
name: "value正常传递",
args: args{
context.WithValue(context.TODO(), k, "world"),
},
stub: func(t *testing.T, ctx context.Context) {
assert.Equal(t, ctx.Value(k).(string), "world")
},
},

{
name: "new Deadline()",
args: args{
ctx: func() context.Context {
ctx, cancel := context.WithDeadline(context.TODO(), time.Date(2022, 1, 1, 1, 1, 1, 1, time.Local))
_ = cancel
return ctx
}(),
},
stub: func(t *testing.T, ctx context.Context) {
deadline, ok := ctx.Deadline()
assert.Equal(t, ok, true)
assert.Equal(t, deadline, time.Date(2022, 1, 1, 1, 1, 1, 1, time.Local))
},
},

{
name: "cancel withtimeout context",
args: args{
ctx: func() context.Context {
now := time.Now()
ctx := context.WithValue(context.Background(), "t", now)
ctx, cancel := context.WithDeadline(ctx, now.Add(1000*time.Microsecond))
go func() {
time.Sleep(100 * time.Microsecond)
cancel()
}()
return ctx
}(),
},

stub: func(t *testing.T, ctx context.Context) {
<-ctx.Done()
duration := time.Since(ctx.Value("t").(time.Time))
if ctx.Err() == context.Canceled {
t.Error("context canceled")
}
if duration < 200*time.Microsecond {
t.Error("timeout cancel ")
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := WithNoCancel(tt.args.ctx)
tt.stub(t, got)
})
}
}