我正在处理一个 http 端点,它将接收来自客户端的请求并阻塞,直到它从另一台服务器收到该请求的“确认”或直到它通过超时。我的代码和服务器之间的通信未包含在此示例中,但您可以假设对于每个请求,最终可能会收到一个 ack。由于许多请求将在短时间内通过我的模块,我不能假设给定的 ack 与我阻止的请求相关。编辑:在这里澄清,因为它引起了一些混乱。控制器从外部来源接收请求和确认。这就是我异步处理它们的原因。/EDIT出于这个原因,如果它们不相关,我的代码会将 acks 放回通道。同样重要的是要注意 http.ListenAndServe 异步调用我的函数。如果请求在超时内被确认,则没有问题。但是,如果 ack 在超时过后出现,它将被添加到通道中并且永远不会被删除。这将导致通道被填满。我害怕使用“取消”通道,因为也有可能不会收到给定请求的 ack,从而导致取消通道也被填满。问题:如何防止延迟确认填充我的频道?/如何识别和删除延迟确认?代码如下。没有 play.golang.org 链接,因为 http.ListenAndServe :/package mainimport ( "fmt" "net/http" "time")const timeout = 10func 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 的新手。请随时在评论中提供其他反馈。
2 回答
ITMISS
TA贡献1871条经验 获得超8个赞
保持一个map
“uuids in process”;当您收到一个/start/
将其添加到地图时,以及当您收到一个ack
(或请求超时时)将其删除时。如果您收到不在地图中的确认,请立即丢弃它。
小心,因为默认情况下映射不是线程安全的。
桃花长相依
TA贡献1860条经验 获得超8个赞
看起来您可能正在尝试以 Akka 的异步风格编写 Go。这是一个艰难的选择;惯用的 Go 应该更容易。缺陷在这里:“我不能假设给定的 ack 与我阻止的请求相关”。
相反,您需要使用简单的顺序步骤处理每个请求,并将 ack 直接发送回其客户端。为此,每个请求都需要自己的服务 goroutine。
- 2 回答
- 0 关注
- 269 浏览
添加回答
举报
0/150
提交
取消