客户端向GraphQL订阅服务器发送关闭信号方式及ctx.Done()触发疑问
GraphQL订阅中ctx.Done()的触发场景解析
我正在开发一个GraphQL服务器,其中包含一个订阅API,以下是我在gqlgen文档中找到的示例代码:
// CurrentTime is the resolver for the currentTime field. func (r *subscriptionResolver) CurrentTime(ctx context.Context) (<-chan *model.Time, error) { // First you'll need to `make()` your channel. Use your type here! ch := make(chan *model.Time) // You can (and probably should) handle your channels in a central place outside of `schema.resolvers.go`. // For this example we'll simply use a Goroutine with a simple loop. go func() { // Handle deregistration of the channel here. Note the `defer` defer close(ch) for { // In our example we'll send the current time every second. time.Sleep(1 * time.Second) fmt.Println("Tick") // Prepare your object. currentTime := time.Now() t := &model.Time{ UnixTime: int(currentTime.Unix()), TimeStamp: currentTime.Format(time.RFC3339), } // The subscription may have got closed due to the client disconnecting. // Hence we do send in a select block with a check for context cancellation. // This avoids goroutine getting blocked forever or panicking, select { case <-ctx.Done(): // This runs when context gets cancelled. Subscription closes. fmt.Println("Subscription Closed") // Handle deregistration of the channel here. `close(ch)` return // Remember to return to end the routine. case ch <- t: // This is the actual send. // Our message went through, do nothing } } }() // We return the channel and no error. return ch, nil }
我想了解接收到ctx.Done()信号时的具体情况:该信号是客户端取消订阅或关闭订阅时发送的?还是可能因闲置超时自动触发?另外,服务端设置的超时是否会触发ctx.Done()信号?
触发ctx.Done()的核心场景:
- 客户端主动终止:当客户端主动取消订阅(调用客户端SDK的取消方法)、关闭连接(比如关闭浏览器标签页、断开WebSocket)时,gqlgen会自动取消当前订阅绑定的Context,触发
ctx.Done()。这是代码注释中提到的最常见场景。 - 服务端闲置超时触发:如果你的GraphQL服务配置了订阅的闲置超时(比如通过gqlgen配置项、底层WebSocket服务器的超时设置),当客户端在指定时间内无任何交互(包括心跳包),服务端会主动终止订阅,此时也会触发
ctx.Done()。 - 服务端主动配置的超时:如果你在Resolver或服务端中间件中,通过
context.WithTimeout或context.WithDeadline给订阅Context设置了超时,当超时时间到达时,Context会被取消,进而触发ctx.Done()。默认情况下gqlgen不会给订阅Context添加超时,需要你主动配置。
补充说明:代码中defer close(ch)的写法很合理,当ctx.Done()触发后,goroutine退出前会关闭channel,能有效避免goroutine泄漏和资源浪费。
内容的提问来源于stack exchange,提问作者mrasoolmirza
相关产品推荐
相关产品推荐

