Keep the recurring SCUM database poll bounded
Each dispatched poll is a durable job with two job log streams, so an unbounded poll history would grow the platform store by roughly two thousand jobs a day per server. A new poll now retires older terminal jobs of the same template together with their job log streams, leaving at most two rows per template while nothing is in flight.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -225,3 +226,61 @@ func TestSCUMQueryProjectionIgnoresUndeclaredTemplateResults(t *testing.T) {
|
||||
t.Fatalf("expected no projected users for an undeclared template, users=%+v err=%v", users, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSCUMQueryJobRetentionKeepsBoundedHistory(t *testing.T) {
|
||||
svc, _, instance, clock := newSCUMQueryIngestFixture(t)
|
||||
aligned := time.Date(2026, 9, 16, 8, 0, 0, 0, time.UTC)
|
||||
*clock = aligned
|
||||
refreshSCUMQueryRunHeartbeat(t, svc, aligned)
|
||||
|
||||
playersJobs := func() []domain.Job {
|
||||
jobs := countSCUMQueryJobs(t, svc, instance.ID)
|
||||
players := make([]domain.Job, 0, len(jobs))
|
||||
for _, job := range jobs {
|
||||
if job.ExecutionInput.Inputs["templateKey"] == "scum.database.players" {
|
||||
players = append(players, job)
|
||||
}
|
||||
}
|
||||
return players
|
||||
}
|
||||
|
||||
var firstJob domain.Job
|
||||
for cycle := 0; cycle < 4; cycle++ {
|
||||
if cycle > 0 {
|
||||
*clock = aligned.Add(time.Duration(cycle) * 61 * time.Second)
|
||||
refreshSCUMQueryRunHeartbeat(t, svc, *clock)
|
||||
}
|
||||
if err := svc.ReconcileSCUMQueryTemplates(instance.ID); err != nil {
|
||||
t.Fatalf("reconcile cycle %d: %v", cycle, err)
|
||||
}
|
||||
for _, job := range playersJobs() {
|
||||
if isTerminalJobState(job.State) {
|
||||
continue
|
||||
}
|
||||
if cycle == 0 {
|
||||
firstJob = job
|
||||
}
|
||||
job.State = domain.JobStateSucceeded
|
||||
job.TerminalAt = *clock
|
||||
if err := svc.store.Jobs().Update(job); err != nil {
|
||||
t.Fatalf("complete query job: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retained := playersJobs()
|
||||
if len(retained) != scumQueryJobRetention {
|
||||
t.Fatalf("expected %d retained player query jobs, got %d", scumQueryJobRetention, len(retained))
|
||||
}
|
||||
for _, job := range retained {
|
||||
if !isTerminalJobState(job.State) {
|
||||
t.Fatalf("retention must not remove in-flight jobs: %+v", job)
|
||||
}
|
||||
}
|
||||
if _, err := svc.store.Jobs().Get(firstJob.ID); !errors.Is(err, repo.ErrNotFound) {
|
||||
t.Fatalf("expected the oldest query job to be retired, err=%v", err)
|
||||
}
|
||||
if _, err := svc.store.LogStreams().Get(jobLogStreamID(firstJob.ID, "stdout")); !errors.Is(err, repo.ErrNotFound) {
|
||||
t.Fatalf("expected retired query job log streams to be removed, err=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user