gpt4 book ai didi

go - 后台打印程序概念/API 和 channel : issue passing jobs to a queue from serveHTTP

转载 作者:IT王子 更新时间:2023-10-29 02:28:17 24 4
gpt4 key购买 nike

在这里已经得到了一些帮助,这让我在我正在尝试的这个概念上取得了进展,但它仍然不太奏效,我遇到了一个我似乎无法解决的冲突。

我在这里尝试在流程图中说明我想要的内容 - 请注意,客户端可以是许多将发送 printjobs 的客户端,因此我们无法回复工作人员当时正在处理我们的工作,但对于大多数会的(高峰期不会,因为打印处理工作需要时间)。

enter image description here

type QueueElement struct {
jobid string
rw http.ResponseWriter
doneChan chan struct{}
}

type GlobalVars struct {
db *sql.DB
wg sync.WaitGroup
jobs chan QueueElement
}

func (gv *GlobalVars) ServeHTTP(w http.ResponseWriter, r *http.Request) {

switch r.URL.Path {
case "/StartJob":
fmt.Printf ("incoming\r\n")

doneC := make(chan struct{}, 1) //Buffered channel in order not to block the worker routine
newPrintJob := QueueElement{
doneChan: doneC,
jobid: "jobid",
}

gv.jobs <- newPrintJob
func(doneChan chan struct{},w http.ResponseWriter) {

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
select {
//If this triggers first, then this waiting goroutine would exit
//and nobody would be listeding the 'doneChan'. This is why it has to be buffered.
case <-ctx.Done():
fmt.Fprintf(w, "job is taking more than 5 seconds to complete\r\n")
fmt.Printf ("took longer than 5 secs\r\n")
case <-doneChan:
fmt.Fprintf(w, "instant reply from serveHTTP\r\n")
fmt.Printf ("instant\r\n")
}
}(doneC,w)

default:
fmt.Fprintf(w, "No such Api")
}
}

func worker(jobs <-chan QueueElement) {
for {
job := <-jobs
processExec ("START /i /b try.cmd")
fmt.Printf ("job done")
// processExec("START /i /b processAndPrint.exe -" + job.jobid)
job.doneChan <- struct{}{}

}
}

func main() {
db, err := sql.Open("sqlite3", "jobs.sqlite")
if err := db.Ping(); err != nil {
log.Fatal(err)
}

db.SetMaxOpenConns(1) // prevents locked database error
_, err = db.Exec(setupSQL)
if err != nil {
log.Fatal(err)
}

// create a GlobalVars instance
gv := GlobalVars{
db : db,
jobs: make(chan QueueElement),
}
go worker (gv.jobs)
// create an http.Server instance and specify our job manager as
// the handler for requests.
server := http.Server{
Handler: &gv,
Addr : ":8888",
}
// start server and accept connections.
log.Fatal(server.ListenAndServe())
}

上面的代码是 serveHTTP 和 worker 在此处帮助下的代码,最初 ServeHTTP 中的 func 是一个 go 例程,在这里对我来说整个冲突都出现了 - 这个概念是在 serveHTTP 中它产生了一个进程如果 worker 能够在 5 秒内及时处理作业,将会得到 worker 的回复。

如果工作能够在 1 秒内完成,我想在 1 秒后立即回复客户,如果需要 3 秒我想在 3 秒后回复,如果超过 5 秒我会发回回复5 秒后(如果工作需要 13 秒,我仍然想在 5 秒后回复)。从现在开始,客户端必须对作业进行轮询 - 但冲突是:

a) 当 ServeHTTP 退出时 - 然后 ResponseWriter 关闭 - 为了能够回复客户端,我们必须将答案写入 ResponseWriter。

b) 如果我阻止 serveHTTP(就像在下面的代码示例中,我没有将 func 称为 go 例程)那么它不仅会影响单个 API 调用,而且似乎会影响之后的所有其他调用,因此第一个调用将被及时正确服务,但在第一个调用之后同时进入的调用将被阻塞操作顺序延迟。

c) 如果我不阻止它 ex - 并将其更改为 go routine :

    gv.jobs <- newPrintJob
go func(doneChan chan struct{},w http.ResponseWriter) {

然后没有延迟 - 可以调用许多 API - 但问题是 serveHTTP 立即存在并因此杀死 ResponseWriter 然后我无法回复客户端。

我不确定如何解决这个冲突,因为我不会对 serveHTTP 造成任何阻塞,所以我可以并行处理所有请求,但仍然能够回复有问题的 ResponseWriter。

有什么方法可以防止 serveHTTP 在函数退出时关闭响应编写器?

最佳答案

是的,您的观点是正确的“c) 如果我不阻止它 ex”

为了保存响应编写器,您不应该在其中调用 go routine。相反,您应该将 ServeHTTP 作为 go-routine 调用,大多数 http 服务器实现都这样做。
这样您就不会阻止任何 api 调用,每个 api 调用将在不同的 go-routine 中运行,并被它们的功能阻止。

由于您的"jobs chan QueueElement" 是单个 channel (不是缓冲 channel ),因此您的所有进程都在"gv.jobs <- newPrintJob" 处被阻塞.
您应该使用缓冲 channel ,以便所有 api 调用都可以将其添加到队列中并根据工作完成或超时获得响应。

拥有缓冲 channel 也可以模拟打印机在现实世界中的内存限制。 (队列长度为 1 为特例)

关于go - 后台打印程序概念/API 和 channel : issue passing jobs to a queue from serveHTTP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56405281/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com