我正在开发一个http端点,该端点将接收来自客户端的请求并阻塞,直到它收到" ack"来自另一台服务器的请求或直到它超时。我的代码和服务器之间的通信不包含在此示例中,但您可以假设对于每个请求,最终可能会收到确认。
由于许多请求会在短时间内通过我的模块,因此我无法假设给定的ack与我阻止的请求相关。 编辑:此处澄清,因为它引起了一些混乱。控制器从外部源接收请求和确认。这就是我异步处理它们的原因。 / EDIT 因此,如果相关信息不对,我的代码会将其放回频道。同样重要的是要注意http.ListenAndServe异步调用我的函数。
如果请求在超时内被激活,则没有问题。但是,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
}
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的新手。您可以在评论中提供其他反馈。
答案 0 :(得分:1)
保持map
“uuids正在进行中”;当您收到/start/
时将其添加到地图中,并在收到ack
时(或请求超时)将其删除。如果您收到不在地图中的确认,请立即将其丢弃。
请注意,因为默认情况下地图不是线程安全的。
答案 1 :(得分:0)
好像你可能试图用Akka的异步风格编写Go。这是一个艰难的选择;惯用Go应该更容易。缺陷在这里:&#34; 我无法假设给定的ack与我阻止的请求相关&#34;。
相反,您需要使用简单的顺序步骤处理每个请求,并将ack直接发送回其客户端。为此,每个请求都需要自己的服务goroutine。