fix: Worker 进程独立 Channel + 进程内指数退避重试
- 每个 Worker 消费者使用独立 AMQP Channel,互不影响 - 用 runWorkerWithRetry 包装每个 Worker,断开自动重连 - 用进程内指数退避重试替代失效的 Nack+DLX 重试机制 - 拓扑声明改用临时 Channel,声明完即关闭
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"feedsystem_video_go/internal/video"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
amqp "github.com/rabbitmq/amqp091-go"
|
||||
)
|
||||
@@ -58,18 +59,28 @@ func (w *CommentWorker) Run(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (w *CommentWorker) handleDelivery(ctx context.Context, d amqp.Delivery) {
|
||||
if err := w.process(ctx, d.Body); err != nil {
|
||||
retryCount := rabbitmq.GetRetryCount(d)
|
||||
if retryCount >= rabbitmq.MaxRetryCount {
|
||||
log.Printf("comment worker: max retries exceeded (%d), moving to DLX: %v", retryCount, err)
|
||||
_ = d.Ack(false)
|
||||
const maxRetries = 3
|
||||
for i := 0; i <= maxRetries; i++ {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
_ = d.Nack(false, true)
|
||||
return
|
||||
default:
|
||||
}
|
||||
log.Printf("comment worker: failed (retry %d/%d): %v", retryCount+1, rabbitmq.MaxRetryCount, err)
|
||||
_ = d.Nack(false, true)
|
||||
if err := w.process(ctx, d.Body); err != nil {
|
||||
if i >= maxRetries {
|
||||
log.Printf("comment worker: 重试 %d 次后仍失败, 丢弃: %v", maxRetries, err)
|
||||
_ = d.Ack(false)
|
||||
return
|
||||
}
|
||||
wait := time.Duration(1<<uint(i)) * time.Second
|
||||
log.Printf("comment worker: 处理失败, %v 后重试 (%d/%d): %v", wait, i+1, maxRetries, err)
|
||||
time.Sleep(wait)
|
||||
continue
|
||||
}
|
||||
_ = d.Ack(false)
|
||||
return
|
||||
}
|
||||
_ = d.Ack(false)
|
||||
}
|
||||
|
||||
func (w *CommentWorker) process(ctx context.Context, body []byte) error {
|
||||
|
||||
@@ -58,18 +58,28 @@ func (w *LikeWorker) Run(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (w *LikeWorker) handleDelivery(ctx context.Context, d amqp.Delivery) {
|
||||
if err := w.process(ctx, d.Body); err != nil {
|
||||
retryCount := rabbitmq.GetRetryCount(d)
|
||||
if retryCount >= rabbitmq.MaxRetryCount {
|
||||
log.Printf("like worker: max retries exceeded (%d), moving to DLX: %v", retryCount, err)
|
||||
_ = d.Ack(false)
|
||||
const maxRetries = 3
|
||||
for i := 0; i <= maxRetries; i++ {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
_ = d.Nack(false, true)
|
||||
return
|
||||
default:
|
||||
}
|
||||
log.Printf("like worker: failed (retry %d/%d): %v", retryCount+1, rabbitmq.MaxRetryCount, err)
|
||||
_ = d.Nack(false, true)
|
||||
if err := w.process(ctx, d.Body); err != nil {
|
||||
if i >= maxRetries {
|
||||
log.Printf("like worker: 重试 %d 次后仍失败, 丢弃: %v", maxRetries, err)
|
||||
_ = d.Ack(false)
|
||||
return
|
||||
}
|
||||
wait := time.Duration(1<<uint(i)) * time.Second
|
||||
log.Printf("like worker: 处理失败, %v 后重试 (%d/%d): %v", wait, i+1, maxRetries, err)
|
||||
time.Sleep(wait)
|
||||
continue
|
||||
}
|
||||
_ = d.Ack(false)
|
||||
return
|
||||
}
|
||||
_ = d.Ack(false)
|
||||
}
|
||||
|
||||
func (w *LikeWorker) process(ctx context.Context, body []byte) error {
|
||||
|
||||
@@ -66,18 +66,28 @@ func (w *NotificationWorker) Run(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (w *NotificationWorker) handleDelivery(ctx context.Context, d amqp.Delivery) {
|
||||
retryCount := rabbitmq.GetRetryCount(d)
|
||||
if err := w.process(ctx, d); err != nil {
|
||||
if retryCount >= rabbitmq.MaxRetryCount {
|
||||
log.Printf("notification worker: max retries, dropping: %v", err)
|
||||
_ = d.Ack(false)
|
||||
const maxRetries = 3
|
||||
for i := 0; i <= maxRetries; i++ {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
_ = d.Nack(false, true)
|
||||
return
|
||||
default:
|
||||
}
|
||||
log.Printf("notification worker: failed (retry %d/%d): %v", retryCount+1, rabbitmq.MaxRetryCount, err)
|
||||
_ = d.Nack(false, true)
|
||||
if err := w.process(ctx, d); err != nil {
|
||||
if i >= maxRetries {
|
||||
log.Printf("notification worker: 重试 %d 次后仍失败, 丢弃: %v", maxRetries, err)
|
||||
_ = d.Ack(false)
|
||||
return
|
||||
}
|
||||
wait := time.Duration(1<<uint(i)) * time.Second
|
||||
log.Printf("notification worker: 处理失败, %v 后重试 (%d/%d): %v", wait, i+1, maxRetries, err)
|
||||
time.Sleep(wait)
|
||||
continue
|
||||
}
|
||||
_ = d.Ack(false)
|
||||
return
|
||||
}
|
||||
_ = d.Ack(false)
|
||||
}
|
||||
|
||||
func (w *NotificationWorker) process(ctx context.Context, d amqp.Delivery) error {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
rediscache "feedsystem_video_go/internal/middleware/redis"
|
||||
"feedsystem_video_go/internal/video"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
amqp "github.com/rabbitmq/amqp091-go"
|
||||
)
|
||||
@@ -57,18 +58,28 @@ func (w *PopularityWorker) Run(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (w *PopularityWorker) handleDelivery(ctx context.Context, d amqp.Delivery) {
|
||||
if err := w.process(ctx, d.Body); err != nil {
|
||||
retryCount := rabbitmq.GetRetryCount(d)
|
||||
if retryCount >= rabbitmq.MaxRetryCount {
|
||||
log.Printf("popularity worker: max retries exceeded (%d), moving to DLX: %v", retryCount, err)
|
||||
_ = d.Ack(false)
|
||||
const maxRetries = 3
|
||||
for i := 0; i <= maxRetries; i++ {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
_ = d.Nack(false, true)
|
||||
return
|
||||
default:
|
||||
}
|
||||
log.Printf("popularity worker: failed (retry %d/%d): %v", retryCount+1, rabbitmq.MaxRetryCount, err)
|
||||
_ = d.Nack(false, true)
|
||||
if err := w.process(ctx, d.Body); err != nil {
|
||||
if i >= maxRetries {
|
||||
log.Printf("popularity worker: 重试 %d 次后仍失败, 丢弃: %v", maxRetries, err)
|
||||
_ = d.Ack(false)
|
||||
return
|
||||
}
|
||||
wait := time.Duration(1<<uint(i)) * time.Second
|
||||
log.Printf("popularity worker: 处理失败, %v 后重试 (%d/%d): %v", wait, i+1, maxRetries, err)
|
||||
time.Sleep(wait)
|
||||
continue
|
||||
}
|
||||
_ = d.Ack(false)
|
||||
return
|
||||
}
|
||||
_ = d.Ack(false)
|
||||
}
|
||||
|
||||
func (w *PopularityWorker) process(ctx context.Context, body []byte) error {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"feedsystem_video_go/internal/middleware/rabbitmq"
|
||||
"feedsystem_video_go/internal/social"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
amqp "github.com/rabbitmq/amqp091-go"
|
||||
@@ -57,18 +58,28 @@ func (w *SocialWorker) Run(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (w *SocialWorker) handleDelivery(ctx context.Context, d amqp.Delivery) {
|
||||
if err := w.process(ctx, d.Body); err != nil {
|
||||
retryCount := rabbitmq.GetRetryCount(d)
|
||||
if retryCount >= rabbitmq.MaxRetryCount {
|
||||
log.Printf("social worker: max retries exceeded (%d), moving to DLX: %v", retryCount, err)
|
||||
_ = d.Ack(false)
|
||||
const maxRetries = 3
|
||||
for i := 0; i <= maxRetries; i++ {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
_ = d.Nack(false, true)
|
||||
return
|
||||
default:
|
||||
}
|
||||
log.Printf("social worker: failed (retry %d/%d): %v", retryCount+1, rabbitmq.MaxRetryCount, err)
|
||||
_ = d.Nack(false, true)
|
||||
if err := w.process(ctx, d.Body); err != nil {
|
||||
if i >= maxRetries {
|
||||
log.Printf("social worker: 重试 %d 次后仍失败, 丢弃: %v", maxRetries, err)
|
||||
_ = d.Ack(false)
|
||||
return
|
||||
}
|
||||
wait := time.Duration(1<<uint(i)) * time.Second
|
||||
log.Printf("social worker: 处理失败, %v 后重试 (%d/%d): %v", wait, i+1, maxRetries, err)
|
||||
time.Sleep(wait)
|
||||
continue
|
||||
}
|
||||
_ = d.Ack(false)
|
||||
return
|
||||
}
|
||||
_ = d.Ack(false)
|
||||
}
|
||||
|
||||
func (w *SocialWorker) process(ctx context.Context, body []byte) error {
|
||||
|
||||
Reference in New Issue
Block a user