Skip to content

Commit

Permalink
add MiddlewareNeverDoneCtx for package ghttp (#3250)
Browse files Browse the repository at this point in the history
  • Loading branch information
gqcn committed Jan 6, 2024
1 parent 5a01798 commit 4f4d2c2
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 1 deletion.
13 changes: 13 additions & 0 deletions net/ghttp/ghttp_middleware_never_done_ctx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package ghttp

// MiddlewareNeverDoneCtx sets the context never done for current process.
func MiddlewareNeverDoneCtx(r *Request) {
r.SetCtx(r.GetNeverDoneCtx())
r.Middleware.Next()
}
90 changes: 90 additions & 0 deletions net/ghttp/ghttp_z_unit_feature_request_ctx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"testing"
"time"

"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/encoding/gbase64"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
Expand Down Expand Up @@ -345,3 +346,92 @@ func Test_Request_Form(t *testing.T) {
}), "john")
})
}

func Test_Request_NeverDoneCtx_Done(t *testing.T) {
var array = garray.New(true)
s := g.Server(guid.S())
s.BindHandler("/done", func(r *ghttp.Request) {
var (
ctx = r.Context()
ticker = time.NewTimer(time.Millisecond * 1500)
)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
array.Append(1)
return
case <-ticker.C:
array.Append(1)
return
}
}
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()

time.Sleep(100 * time.Millisecond)

c := g.Client()
c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
gtest.C(t, func(t *gtest.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
go func() {
result := c.GetContent(ctx, "/done")
fmt.Println(result)
}()
time.Sleep(time.Millisecond * 100)

t.Assert(array.Len(), 0)
cancel()

time.Sleep(time.Millisecond * 500)
t.Assert(array.Len(), 1)
})
}

func Test_Request_NeverDoneCtx_NeverDone(t *testing.T) {
var array = garray.New(true)
s := g.Server(guid.S())
s.Use(ghttp.MiddlewareNeverDoneCtx)
s.BindHandler("/never-done", func(r *ghttp.Request) {
var (
ctx = r.Context()
ticker = time.NewTimer(time.Millisecond * 1500)
)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
array.Append(1)
return
case <-ticker.C:
array.Append(1)
return
}
}
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()

time.Sleep(100 * time.Millisecond)

c := g.Client()
c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
gtest.C(t, func(t *gtest.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
go func() {
result := c.GetContent(ctx, "/never-done")
fmt.Println(result)
}()
time.Sleep(time.Millisecond * 100)

t.Assert(array.Len(), 0)
cancel()

time.Sleep(time.Millisecond * 1500)
t.Assert(array.Len(), 1)
})
}
6 changes: 5 additions & 1 deletion os/gctx/gctx_never_done.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ func (c *neverDoneCtx) Err() error {
}

// NeverDone wraps and returns a new context object that will be never done,
// which forbids the context manually done, to make the context can be propagated to asynchronous goroutines.
// which forbids the context manually done, to make the context can be propagated
// to asynchronous goroutines.
//
// Note that, it does not affect the closing (canceling) of the parent context,
// as it is a wrapper for its parent, which only affects the next context handling.
func NeverDone(ctx context.Context) context.Context {
return &neverDoneCtx{ctx}
}

0 comments on commit 4f4d2c2

Please sign in to comment.