Http Golang将无法读取的项目清理出通道

Http Golang将无法读取的项目清理出通道,http,asynchronous,go,Http,Asynchronous,Go,我正在处理一个http端点,该端点将接收来自客户端的请求并阻塞,直到它从另一个服务器接收到该请求的“ack”或直到它通过超时。我的代码和服务器之间的通信不包括在这个示例中,但是您可以假设对于每个请求,最终可能会收到一个ack 由于许多请求将在短时间内通过我的模块,我不能假设给定的ack与我阻塞的请求相关编辑:此处有澄清,因为它引起了一些混乱。控制器从外部源接收请求和确认。这就是为什么我不同步地处理它们/EDIT因此,如果ACK不相关,我的代码会将它们放回频道。还需要注意的是,http.Liste

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

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

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

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

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

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)
}
主程序包
进口(
“fmt”
“net/http”
“时间”
)
常数超时=10
func startEndpoint(w http.ResponseWriter,r*http.Request){
var ack字符串
计时器:=time.NewTimer(time.Second*超时)
延迟计时器。停止()
m:=r.RequestURI[len(“/start/”):]
格式打印(m)
回收:
为了{
挑选{

case ack=保留一个“uuids in process”的
map
;当您收到
/start/
时,将其添加到map,当您收到
ack
(或当请求超时)时,将其删除。如果您收到的ack不在map中,则立即放弃它


请小心,因为映射在默认情况下不是线程安全的。

看起来您可能正在尝试使用Akka的异步样式编写Go。这是一个艰难的选择;惯用Go应该更容易。缺陷在于:“我不能假设给定的ack与我阻塞的请求相关”


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

如果您无法将ack与请求关联,则ack完全无用。否?在请求的同一通道上处理ack。使用令牌来标识e请求(生成一个uuid并将其传递)。ack将有一个与请求匹配的uuid(或者在本例中是一个名称字符串)。在“注意”中,我使用了“bob”作为将请求与ack匹配的名称字符串。问题是ack可能在请求超时后出现,或者根本不会出现。问题是我如何处理延迟/缺失的ack?这个答案解决了我思考中的根本问题:我在寻找一种跟踪哪些ack有效和无效的方法。更有效的方法是跟踪哪些请求是有效的,并使所有不相关的ACK无效。我感谢您的回答。我的问题的措辞似乎很糟糕。在这种情况下,有三个交互服务:发送请求的客户端、提供代码的控制器,以及一组向con发送ACK的外部服务器当工作完成时,troller。从控制器的角度来看,随机请求和ACK一直在到达,并且不一定按特定的顺序。因此,没有一种“顺序”方法来处理请求和ACK。我希望这能澄清这种情况。