Fail orphaned suggestion batches before reporting the deck's active batch
Deck returned a pending or running batch's job id without checking that the job was still queued or running, so after a restart failed the job the page polled a dead job as the active batch. Deck and startBatch now share activeBatch, which runs FailOrphanedSuggestionBatches before reading the active batch; Deck therefore uses a write transaction. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ package suggest_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -479,6 +480,42 @@ func TestDeckReportsTheActiveBatch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeckFailsBatchInterruptedByRestart(t *testing.T) {
|
||||
e := newEnv(t)
|
||||
e.seedDeck(t, "Pho")
|
||||
b, err := e.svc.StartBatch(t.Context(), suggest.TriggerManual)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// A previous process claimed the job and started the batch, then
|
||||
// stopped before recording its end.
|
||||
now := store.Now().String()
|
||||
if _, err := db.New(e.st.Writer).ClaimNextJob(t.Context(), sql.NullString{String: now, Valid: true}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n, err := db.New(e.st.Writer).StartSuggestionBatch(t.Context(), db.StartSuggestionBatchParams{UpdatedAt: now, ID: b.ID}); err != nil || n != 1 {
|
||||
t.Fatalf("start batch: %d rows, %v", n, err)
|
||||
}
|
||||
e.start(t) // fails the running job as interrupted
|
||||
if job := e.waitJob(t, b.JobID); job.Status != jobs.StatusFailed {
|
||||
t.Fatalf("job status = %s, want failed", job.Status)
|
||||
}
|
||||
|
||||
deck, err := e.svc.Deck(t.Context())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if deck.ActiveBatch != nil {
|
||||
t.Errorf("active batch = %+v after its job failed, want nil", deck.ActiveBatch)
|
||||
}
|
||||
if len(deck.Suggestions) != 1 {
|
||||
t.Errorf("deck has %d suggestions, want 1", len(deck.Suggestions))
|
||||
}
|
||||
if got := e.batchStatus(t, b.ID); got != suggest.BatchFailed {
|
||||
t.Errorf("interrupted batch status = %s, want failed", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeckLeavesOutDinnersNoLongerSuggested(t *testing.T) {
|
||||
e := newEnv(t)
|
||||
ids := e.seedDeck(t, "Pho", "Ramen")
|
||||
|
||||
Reference in New Issue
Block a user