mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-01 07:21:17 +00:00
fix(artwork): restart the retry budget on re-enqueue
The conflict clause updated only priority and retry_at, so a row that already existed kept its original attempts and enqueued_at. The worker measures the 12h give-up budget from enqueued_at, so any row that had been pending across a longer gap — a server left off, an upgrade, a laptop asleep — gave up on its very first attempt and settled absent. The manual re-resolve endpoint is the sharpest case: it clears artwork state and re-queues, but inherited the old row's spent window, so a deliberate retry got one shot. A fresh request now gets a fresh budget, with the mock updated to match.
This commit is contained in:
parent
2207211997
commit
2ee2b2d66f
@ -26,9 +26,12 @@ func NewArtworkQueueRepository(ctx context.Context, db dbx.Builder) model.Artwor
|
||||
return r
|
||||
}
|
||||
|
||||
// Enqueue also restarts the retry budget the worker measures from enqueued_at, so a fresh
|
||||
// request never inherits an old row's spent window and give up on its first attempt.
|
||||
func (r *artworkQueueRepository) Enqueue(items ...model.ArtworkQueueItem) error {
|
||||
return r.enqueue(`ON CONFLICT (item_kind, item_id, image_type) DO UPDATE SET
|
||||
priority = MAX(priority, excluded.priority), retry_at = excluded.retry_at`, items)
|
||||
priority = MAX(priority, excluded.priority), retry_at = excluded.retry_at,
|
||||
attempts = 0, enqueued_at = excluded.enqueued_at`, items)
|
||||
}
|
||||
|
||||
// EnqueueBump raises priority like Enqueue but leaves an existing row's retry_at intact, so a
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"github.com/navidrome/navidrome/model"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/pocketbase/dbx"
|
||||
)
|
||||
|
||||
var _ = Describe("ArtworkQueueRepository", func() {
|
||||
@ -96,7 +97,7 @@ var _ = Describe("ArtworkQueueRepository", func() {
|
||||
Expect(repo.MarkFailedIfUnchanged("al", "m1", model.ImageTypePrimary, original, future)).To(Succeed())
|
||||
got, _ = repo.DequeueBatch(10)
|
||||
Expect(got).To(HaveLen(1), "the fresh re-enqueue stays immediately eligible")
|
||||
Expect(got[0].Attempts).To(Equal(1), "the stale failure must not bump attempts")
|
||||
Expect(got[0].Attempts).To(BeZero(), "re-enqueue clears attempts, and the stale failure must not bump them")
|
||||
current := got[0].RetryAt
|
||||
|
||||
// Failing with the current retry_at applies the backoff and bumps attempts.
|
||||
@ -107,6 +108,24 @@ var _ = Describe("ArtworkQueueRepository", func() {
|
||||
Expect(all).To(Equal(int64(1)))
|
||||
})
|
||||
|
||||
It("Enqueue restarts the retry budget an existing row had spent", func() {
|
||||
Expect(repo.Enqueue(item("al", "e1", model.ArtworkPriorityScan))).To(Succeed())
|
||||
Expect(repo.MarkFailed("al", "e1", model.ImageTypePrimary, time.Now().Add(-time.Hour))).To(Succeed())
|
||||
stale := time.Now().Add(-48 * time.Hour)
|
||||
_, err := GetDBXBuilder().NewQuery("UPDATE artwork_queue SET enqueued_at = {:t} WHERE item_id = 'e1'").
|
||||
Bind(dbx.Params{"t": stale}).Execute()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(repo.Enqueue(item("al", "e1", model.ArtworkPriorityScan))).To(Succeed())
|
||||
|
||||
got, err := repo.DequeueBatch(10)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(got).To(HaveLen(1))
|
||||
Expect(got[0].EnqueuedAt).To(BeTemporally("~", time.Now(), time.Minute),
|
||||
"a re-request must not inherit a spent 12h window and give up on its first attempt")
|
||||
Expect(got[0].Attempts).To(BeZero())
|
||||
})
|
||||
|
||||
It("deletes on completion and counts", func() {
|
||||
Expect(repo.Enqueue(item("al", "c1", 0))).To(Succeed())
|
||||
n, _ := repo.Count()
|
||||
|
||||
@ -40,6 +40,8 @@ func (m *MockArtworkQueueRepo) Enqueue(items ...model.ArtworkQueueItem) error {
|
||||
if prev, ok := m.Data[k]; ok {
|
||||
prev.Priority = max(prev.Priority, it.Priority)
|
||||
prev.RetryAt = now
|
||||
prev.Attempts = 0
|
||||
prev.EnqueuedAt = now
|
||||
m.Data[k] = prev
|
||||
continue
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user