英文:
How to implement a function using channels
问题
有一个在goroutine中运行的函数:
func (c *controlUC) WebhookPool() {
for {
if len(c.webhookPool) == 0 {
continue
}
for i := 0; i < len(c.webhookPool); i++ {
if !c.webhookPool[i].LastSentTime.IsZero() && time.Now().Before(c.webhookPool[i].LastSentTime.Add(GetDelayBySentCount(c.webhookPool[i].SendCount))) {
continue
}
var headers = make(map[string]string)
headers["Content-type"] = "application/json"
_, statusCode, err := c.fhttpClient.Request("POST", c.webhookPool[i].Path, c.webhookPool[i].Body, nil, headers)
if err != nil {
c.logger.Error(err)
return
}
if statusCode != 200 {
if c.webhookPool[i].SendCount >= 2 {
c.webhookPool = append(c.webhookPool[:i], c.webhookPool[i+1:]...)
i--
continue
}
c.webhookPool[i].SendCount++
} else {
c.webhookPool = append(c.webhookPool[:i], c.webhookPool[i+1:]...)
i--
continue
}
c.webhookPool[i].LastSentTime = time.Now()
}
}
}
// webhookPool []models.WebhookPoolElem
type WebhookPoolElem struct {
SendCount int
LastSentTime time.Time
Path string
Body []byte
}
webhookPoolElem
元素被添加到c.webhookpool
中,然后向服务器发送请求(路径取自WebhookPoolElem.path
)。如果服务器返回的状态码不是200,那么我需要在X
秒后再次发送请求(根据SendCount
从GetDelayBySentCount()
中返回不同的时间)。尝试次数是有限的(c.webhookpool[i].SendCount >= 2
)。
但也许这个函数需要通过通道来实现?如果是这样,应该如何实现?
英文:
There is a function that is running in goroutine:
func (c *controlUC) WebhookPool() {
for {
if len(c.webhookPool) == 0 {
continue
}
for i := 0; i < len(c.webhookPool); i++ {
if !c.webhookPool[i].LastSentTime.IsZero() && time.Now().Before(c.webhookPool[i].LastSentTime.Add(GetDelayBySentCount(c.webhookPool[i].SendCount))) {
continue
}
var headers = make(map[string]string)
headers["Content-type"] = "application/json"
_, statusCode, err := c.fhttpClient.Request("POST", c.webhookPool[i].Path, c.webhookPool[i].Body, nil, headers)
if err != nil {
c.logger.Error(err)
return
}
if statusCode != 200 {
if c.webhookPool[i].SendCount >= 2 {
c.webhookPool = append(c.webhookPool[:i], c.webhookPool[i+1:]...)
i--
continue
}
c.webhookPool[i].SendCount++
} else {
c.webhookPool = append(c.webhookPool[:i], c.webhookPool[i+1:]...)
i--
continue
}
c.webhookPool[i].LastSentTime = time.Now()
}
}
}
// webhookPool []models.WebhookPoolElem
type WebhookPoolElem struct {
SendCount int
LastSentTime time.Time
Path string
Body []byte
}
The webhookPoolElem
element is added to c.webhookpool
, after which a request is sent to the server (the path is taken from WebhookPoolElem.path
). If the server returned a non - 200 200, then I need to send the request again, after X
seconds (taken from GetDelayBySentCount()
, depending on SendCount
returns different times). The number of attempts is limited (c.webhookpool[i].SendCount >= 2
)
But maybe this function needs to be done through channels? If so, how?
答案1
得分: 1
假设controlUC
接收器有一个字段webhookPool chan WebhookPoolElem
,并且使用webhookPool: make(chan WebhookPoolElem, n)
进行初始化,其中n
是缓冲区大小。
你可以接收元素,并且可以将c.webhookPool[i]
替换为elem
。重写如下:
func (c *controlUC) WebhookPool() {
for {
elem, open := <-c.webhookPool
if !open {
return
}
if !elem.LastSentTime.IsZero() && time.Now().Before(elem.LastSentTime.Add(GetDelayBySentCount(elem.SendCount))) {
continue
}
// 我省略了http请求
if statusCode != 200 {
if elem.SendCount >= 2 {
// 从通道中丢弃消息,无需执行任何操作
continue
}
elem.SendCount++
elem.LastSentTime = time.Now()
c.webhookPool <- elem // 再次入队
}
}
}
我建议使用带缓冲的通道,这样最后的发送操作c.webhookPool <- elem
不会阻塞,但最好将发送操作放在select
语句中,这样如果发送无法进行,无论缓冲区如何,goroutine都不会阻塞:
select {
case c.webhookPool <- elem:
// 发送成功
default:
// 无法发送
}
英文:
Lets say controlUC
receiver has a field webhookPool chan WebhookPoolElem
and init as webhookPool: make(chan WebhookPoolElem, n)
with n
as buffer.
You can receive elements and more or less replace c.webhookPool[i]
to elem
. Rewrite like this:
func (c *controlUC) WebhookPool() {
for {
elem, open := <-c.webhookPool
if !open {
return
}
if !elem.LastSentTime.IsZero() && time.Now().Before(elem.LastSentTime.Add(GetDelayBySentCount(elem.SendCount))) {
continue
}
// I omit http request
if statusCode != 200 {
if elem.SendCount >= 2 {
// drop message from channel, no need to do anything
continue
}
elem.SendCount++
elem.LastSentTime = time.Now()
c.webhookPool <- elem // enqueue again
}
}
I suggest buffered channel so the last send c.webhookPool <- elem
does not block, but it's best if you place the send in a select
so if the send can not proceed regardless of the buffer, the goroutine doesn't block:
select {
case c.webhookPool <- elem:
// success
default:
// can not send
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论