我正在处理一个 http 端点,它将接收来自客户端的请求并阻塞,直到它从另一台服务器收到该请求的“确认”或直到它通过超时。我的代码和服务器之间的通信未包含在此示例中,但您可以假设对于每个请求,最终可能会收到一个 ack。



如果请求在超时内被确认,则没有问题。但是,如果 ack 在超时过后出现,它将被添加到通道中并且永远不会被删除。这将导致通道被填满。我害怕使用“取消”通道,因为也有可能不会收到给定请求的 ack,从而导致取消通道也被填满。


问题:如何防止延迟确认填充我的频道?/如何识别和删除延迟确认?


代码如下。没有 play.golang.org 链接,因为 http.ListenAndServe :/


package main


import (

    "fmt"

    "net/http"

    "time"

)


const timeout = 10


func startEndpoint(w http.ResponseWriter, r *http.Request) {

    var ack string

    timer := time.NewTimer(time.Second * timeout)

    defer timer.Stop()


    m := r.RequestURI[len("/start/"):]

    fmt.Print(m)

AckRecycle:

    for {

        select {

        case ack = <-acks:

            if ack == m {

                //What we found was our own ack

                fmt.Print("+")

                w.Write([]byte("Ack received for " + ack))

                break AckRecycle

            } else {

                //What we found on the channel wasn't for us

                fmt.Print(".")

                time.Sleep(time.Millisecond * 100)

                acks <- ack

            }

        case <-timer.C:

            //We ran out of time waiting for our ack

            w.Write([]byte("Timeout waiting for " + m))

            break AckRecycle

        default:

            //Channel was empty

            fmt.Print("-")

            time.Sleep(time.Millisecond * 100)

        }

    }

    return

}


func ackEndpoint(w http.ResponseWriter, r *http.Request) {

    ack := r.RequestURI[len("/ack/"):]

    acks <- ack

    fmt.Print("Ack for " + ack)

    w.Write([]byte("Thanks!"))

    return

}


注意:要对此进行测试,请在本地计算机上运行它。Curl/Wget127.0.0.1:8888/start/bob然后是 Curl/Wget 127.0.0.1:8888/ack/bob。您可以用任何字符串替换 bob 以查看行为。


我是 Go 的新手。请随时在评论中提供其他反馈。