Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Notifier spins without backoff when the Start context ends by deadline

Đã đóng Phù hợp với người mới
#1,493 1 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Một pull request liên quan đã được merge.

  • #1495 của @brandur — đã merge

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
62/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
go, postgresql
Lĩnh vực
backend, databases

Hướng nghiên cứu

Bắt đầu từ internal/notifier/notifier.go, tại vòng lặp kết nối lại gọi n.listenAndWait(ctx) và kiểm tra errors.Is(err, context.Canceled). Cách sửa là dừng vòng lặp khi ctx.Err() khác nil, đồng thời kiểm tra các điểm thoát context.Canceled khác trong cùng tệp. Việc được coi là xong khi một context chạm tới deadline làm Start kết thúc mà không ghi log Error running listener lặp lại, được chứng minh bằng một bài kiểm thử dùng context.WithTimeout ngắn.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Summary

If the context passed to Client.Start ends by deadline rather than cancellation, the notifier's reconnect loop spins with no backoff and logs Error running listener (will attempt reconnect after backoff) hundreds of thousands of times per second, forever.

Where

internal/notifier/notifier.go (v0.47.0, and unchanged on master at 2f6b27e):

for attempt := 0; ; attempt++ {
    if err := n.listenAndWait(ctx); err != nil {
        if errors.Is(err, context.Canceled) {
            break
        }
        sleepDuration := serviceutil.ExponentialBackoff(attempt, serviceutil.MaxAttemptsBeforeResetDefault)
        n.Logger.ErrorContext(ctx, n.Name+": Error running listener (will attempt reconnect after backoff)", ...)
        ...
        serviceutil.CancellableSleep(ctx, sleepDuration)
    }
}

Once ctx is done with context.DeadlineExceeded, listenAndWait fails immediately, the context.Canceled check doesn't match, and CancellableSleep returns immediately because ctx is already done. The loop never exits and never sleeps.

Reproduction
  1. Create a client against a healthy Postgres.
  2. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second), then client.Start(ctx).
  3. Wait past the deadline.

We measured 379,487 Error running listener lines in the 2 seconds after the deadline, and 0 when the same context is cancelled instead. Left running, it wrote a ~476 GB log in about 6 hours before we found it.

Suggested fix

Exit the loop when the context is done for any reason, e.g. if ctx.Err() != nil { break } (or check context.DeadlineExceeded too). The other errors.Is(err, context.Canceled) exits in the notifier may deserve the same treatment.

Workaround

Start River on a context that can only end by cancellation, e.g. runCtx, cancel := context.WithCancel(context.WithoutCancel(ctx)); context.AfterFunc(ctx, cancel).

Ngôn ngữ chính
Go
Star
5.8k
Fork
188
Merge trung bình
22 giờ 44 phút
Pull request đã merge (30 ngày)
95

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của riverqueue/river

Tất cả issue của riverqueue/river

Issue tương tự

Thêm issue về Go

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.