Golang clean items out of channel 不会被读取

Golang clean items out of channel that will not be read

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

由于许多请求将在短时间内通过我的模块,我不能假设给定的 ack 与我阻止的请求相关。 编辑: 在这里澄清,因为它引起了一些混乱。控制器从外部源接收请求和确认。这就是我异步处理它们的原因。 /EDIT 出于这个原因,如果确认不相关,我的代码会将确认放回频道。同样重要的是要注意 http.ListenAndServe 异步调用我的函数。

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

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

代码如下。没有 play.golang.org link 因为 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
}

var acks = make(chan string, 10)

func main() {
    http.HandleFunc("/ack/", ackEndpoint)
    http.HandleFunc("/start/", startEndpoint)

    http.ListenAndServe("127.0.0.1:8888", nil)
}

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

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

保持 map 的 "uuids in process";当您收到 /start/ 时将其添加到地图中,当您收到 ack 时(或请求超时时)将其删除。如果您收到不在地图中的确认,请立即丢弃它。

请注意,默认情况下地图不是线程安全的。

看来您可能正在尝试以 Akka 的异步风格编写 Go。这是一个艰难的选择;惯用的 Go 应该更容易。缺陷在这里:“我不能假设给定的确认与我阻止的请求相关”。

相反,您需要通过简单的顺序步骤处理每个请求,并将 ack 直接发送回其客户端。为此,每个请求都需要自己的服务 goroutine。