使用 HTTP 请求上下文管理通道

sys*_*cll 5 concurrency http channel go

我有一个基本的 HTTP 服务器,它接受请求并从数据存储返回数据。

每个 HTTP 请求都会执行以下操作:

  1. 创建一个带有超时时间的上下文
  2. 创建读取请求(自定义类型)
  3. 将读取请求推送到通道
  4. 等待响应并提供数据

这是基本的伪代码:

package main

import (
    "context"
    "net/http"
    "time"
)

type dataRequest struct {
    data chan string
    ctx  context.Context
}

func handler(reqStream chan dataRequest) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
        defer cancel()

        req := dataRequest{
            data: make(chan string),
            ctx:  ctx,
        }

        select {
        case reqStream <- req:
            // request pushed to que
        case <-ctx.Done():
            // don't push onto reqStream if ctx done
        }

        select {
        case <-ctx.Done():
            // don't try and serve content if ctx done
        case data := <-req.data:
            // return data to client
        }

    }
}

func main() {
    dataReqs := make(chan dataRequest)
    go func() {
        for {
            select {
            case req := <-dataReqs:
                select {
                case <-req.ctx.Done():
                    // don't push onto data channel if ctx done
                case req.data <- "some data":
                    // get data from store
                }
            }
        }
    }()
    http.HandleFunc("/", handler(dataReqs))
    http.ListenAndServe(":8080", nil)
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,由于超出截止日期或客户端取消请求,上下文可能随时完成,我当前的方法对于在多个地方处理此问题是否正确,或者是否有更优雅的解决方案?

Gal*_*aim 0

在我看来,它会起作用。很少评论——

  1. 你可以return在第一种情况下<- ctx.Done()
  2. 您已经在数据存储处理程序中等待req.ctx.Done(),因此您可以完全删除第一个select {}语句并仅发布到数据请求通道。不确定在极少数情况下,当上下文在请求发布之前就已经完成时,性能会受到影响......