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

时间:2017-04-28 14:55:19

标签: http go concurrency channels

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

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

  1. 创建超时的上下文
  2. 创建阅读请求(自定义类型)
  3. 将阅读请求推送到频道
  4. 等待回复并提供数据
  5. 这是基本的伪代码:

    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)
    }
    

    我的问题是,因为上下文可能会因为超出截止日期或客户端取消请求而随时完成,我目前的方法是否适合在多个地方处理此问题或是否有更优雅的解决方案?

1 个答案:

答案 0 :(得分:0)

在我看来它会起作用。 几条评论 -

  1. 您可以在return
  2. 的第一个案例中<- ctx.Done()
  3. 您已经在数据存储处理程序中等待req.ctx.Done(),因此您可以完全删除第一个select {}语句,然后只发布到数据请求通道。在请求发布前很早就完成上下文的情况下,不确定性能命中...