console: an expired open is classified by the fenced record before any abort, so an open that lands in the fence is opened with no abort left behind
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 file changed,
+17
−0
internal/console/selfserve_job.go+17 −0
diff --git a/internal/console/selfserve_job.go b/internal/console/selfserve_job.go| index 037c85678..f0a0d803d 100644 |
| --- a/internal/console/selfserve_job.go |
| +++ b/internal/console/selfserve_job.go |
| @@ -600,6 +600,23 @@ func (s *Server) selfServeExpiryAction(ctx context.Context, t *leaseToken, row * |
| if !row.AbortRequestedAt.IsZero() { |
| return false, nil |
| } |
| + if out, conf := selfServeOutstanding(row); out && !conf && row.Request.Kind == "open" { |
| + // The open's write may still land: the expiry is decided on the |
| + // request and classified by the fenced record (its receipt opens |
| + // the move; absent, the void requests the abort), never an abort |
| + // first that an open landing in the fence would leave behind. |
| + if !row.Request.Expired { |
| + TestHooks.point("open:expire") |
| + if _, err := s.store.ExpireSelfServeRequest(row.ID, row.Request.Nonce, row.Request.Deadline, row.Request.CutRequestedAt); err != nil { |
| + return true, err |
| + } |
| + } |
| + if pr, err := s.store.selfServeRequest(row.ID); err != nil { |
| + return true, err |
| + } else if pr != nil && pr.Expired && !pr.Consumed { |
| + return true, s.selfServeExpired(ctx, t, row) |
| + } |
| + } |
| return true, s.selfServeAbort(row, s.selfServeExpiryReason(ctx, row, rec, now), now) |
| } |