···9696// ErrEventGap is returned when an event is received with a since that doesn't match the current rev
9797var ErrEventGap = fmt.Errorf("buffered event revs did not line up")
98989999+// ErrAlreadyProcessed is returned when attempting to buffer an event that has already been accounted for (rev older than current)
100100+var ErrAlreadyProcessed = fmt.Errorf("event already accounted for")
101101+99102var tracer = otel.Tracer("backfiller")
100103101104type BackfillOptions struct {
···500503 }
501504502505 buffered, err := bf.BufferOps(ctx, evt.Repo, evt.Since, evt.Rev, ops)
503503- if err != nil {
506506+ if err != nil && !errors.Is(err, ErrAlreadyProcessed) {
504507 return fmt.Errorf("buffer ops failed: %w", err)
505508 }
506509
+10
backfill/gormstore.go
···154154 return false, fmt.Errorf("invalid job state: %q", j.state)
155155 }
156156157157+ if j.rev >= rev {
158158+ // we've already accounted for this event
159159+ return false, ErrAlreadyProcessed
160160+ }
161161+157162 j.bufferOps(&opSet{since: since, rev: rev, ops: ops})
158163 return true, nil
159164}
···317322 if opset.since == nil {
318323 // TODO: what does this mean?
319324 return fmt.Errorf("nil since in event after backfill: %w", ErrEventGap)
325325+ }
326326+327327+ if j.rev > *opset.since {
328328+ // we've already accounted for this event
329329+ continue
320330 }
321331322332 if j.rev != *opset.since {