4 回答

TA貢獻1828條經(jīng)驗 獲得超13個贊
我建議始終控制您的戈魯丁,以避免內(nèi)存和系統(tǒng)耗盡。如果您收到請求激增,并且開始不受控制地生成goroutines,則系統(tǒng)可能很快就會關(guān)閉。
在那些需要立即返回200Ok的情況下,最好的方法是創(chuàng)建一個消息隊列,因此服務(wù)器只需要在隊列中創(chuàng)建一個作業(yè)并返回ok和忘記。其余部分將由使用者異步處理。
創(chuàng)建者(HTTP 服務(wù)器)>>>隊列>>>使用者
通常,隊列是外部資源 (RabbitMQ, AWS SQS...),但出于教學(xué)目的,您可以使用與消息隊列相同的通道實現(xiàn)相同的效果。
在示例中,您將看到我們?nèi)绾蝿?chuàng)建一個通道來傳達 2 個進程。然后,我們啟動將從通道讀取的工作進程,然后使用將寫入通道的處理程序啟動服務(wù)器。
嘗試在發(fā)送 curl 請求時使用緩沖區(qū)大小和作業(yè)時間。
package main
import (
"fmt"
"log"
"net/http"
"time"
)
/*
$ go run .
curl "http://localhost:8080?user_id=1"
curl "http://localhost:8080?user_id=2"
curl "http://localhost:8080?user_id=3"
curl "http://localhost:8080?user_id=....."
*/
func main() {
queueSize := 10
// This is our queue, a channel to communicate processes. Queue size is the number of items that can be stored in the channel
myJobQueue := make(chan string, queueSize) // Search for 'buffered channels'
// Starts a worker that will read continuously from our queue
go myBackgroundWorker(myJobQueue)
// We start our server with a handler that is receiving the queue to write to it
if err := http.ListenAndServe("localhost:8080", myAsyncHandler(myJobQueue)); err != nil {
panic(err)
}
}
func myAsyncHandler(myJobQueue chan<- string) http.HandlerFunc {
return func(rw http.ResponseWriter, r *http.Request) {
// We check that in the query string we have a 'user_id' query param
if userID := r.URL.Query().Get("user_id"); userID != "" {
select {
case myJobQueue <- userID: // We try to put the item into the queue ...
rw.WriteHeader(http.StatusOK)
rw.Write([]byte(fmt.Sprintf("queuing user process: %s", userID)))
default: // If we cannot write to the queue it's because is full!
rw.WriteHeader(http.StatusInternalServerError)
rw.Write([]byte(`our internal queue is full, try it later`))
}
return
}
rw.WriteHeader(http.StatusBadRequest)
rw.Write([]byte(`missing 'user_id' in query params`))
}
}
func myBackgroundWorker(myJobQueue <-chan string) {
const (
jobDuration = 10 * time.Second // simulation of a heavy background process
)
// We continuosly read from our queue and process the queue 1 by 1.
// In this loop we could spawn more goroutines in a controlled way to paralelize work and increase the read throughput, but i don't want to overcomplicate the example.
for userID := range myJobQueue {
// rate limiter here ...
// go func(u string){
log.Printf("processing user: %s, started", userID)
time.Sleep(jobDuration)
log.Printf("processing user: %s, finisehd", userID)
// }(userID)
}
}

TA貢獻1860條經(jīng)驗 獲得超8個贊
您無需處理“戈魯丁清理”,您只需啟動戈魯丁,當(dāng)作為戈魯廷返回的功能啟動時,它們將被清除。引用規(guī)范:圍棋聲明:
當(dāng)函數(shù)終止時,其戈魯廷也終止。如果函數(shù)具有任何返回值,則在函數(shù)完成時將丟棄這些返回值。
所以你所做的很好。但請注意,您啟動的 goroutine 不能使用或假定有關(guān)請求 () 和響應(yīng)編寫器 () 的任何內(nèi)容,您只能在從處理程序返回之前使用它們。r
w
另請注意,您不必編寫 ,如果您從處理程序返回而不寫入任何內(nèi)容,則假定為成功并將自動發(fā)送回去。http.StatusOK
HTTP 200 OK
查看相關(guān)/可能的重復(fù)項:在另一個戈魯廷上運行的 Webhook 進程

TA貢獻1873條經(jīng)驗 獲得超9個贊
沒有“戈魯丁清潔”,你可以使用網(wǎng)絡(luò)鉤子或像gocraft這樣的后臺工作。我能想到的使用你的解決方案的唯一方法是將同步包用于學(xué)習(xí)目的。
func DefaultHandler(w http.ResponseWriter, r *http.Request) {
// Some DB calls
// Some business logics
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
// some Task taking 5 sec
}()
w.WriteHeader(http.StatusOK)
wg.wait()
}

TA貢獻1865條經(jīng)驗 獲得超7個贊
您可以等待戈魯廷完成使用:&sync.WaitGroup
// BusyTask
func BusyTask(t interface{}) error {
var wg = &sync.WaitGroup{}
wg.Add(1)
go func() {
// busy doing stuff
time.Sleep(5 * time.Second)
wg.Done()
}()
wg.Wait() // wait for goroutine
return nil
}
// this will wait 5 second till goroutune finish
func main() {
fmt.Println("hello")
BusyTask("some task...")
fmt.Println("done")
}
另一種方法是將 a 附加到戈魯丁并超時。context.Context
//
func BusyTaskContext(ctx context.Context, t string) error {
done := make(chan struct{}, 1)
//
go func() {
// time sleep 5 second
time.Sleep(5 * time.Second)
// do tasks and signle done
done <- struct{}{}
close(done)
}()
//
select {
case <-ctx.Done():
return errors.New("timeout")
case <-done:
return nil
}
}
//
func main() {
fmt.Println("hello")
ctx, cancel := context.WithTimeout(context.TODO(), 2*time.Second)
defer cancel()
if err := BusyTaskContext(ctx, "some task..."); err != nil {
fmt.Println(err)
return
}
fmt.Println("done")
}
- 4 回答
- 0 關(guān)注
- 110 瀏覽
添加回答
舉報