You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Abandon-path forensics record target_session_id = 0 instead of the real SPID (or NULL) #2884
Every ABANDONED row written by the V109 forensics (#2864) so far records target_session_id = 0 — not a valid SPID — while the other four forensic columns populate correctly. Three consecutive production abandonments on the same collector all show it:
Successful runs DO record real session ids (hundreds per 5-minute window on all three stores within minutes of the deploy), so the write path works in general — the zero appears specifically on the abandon path.
Why it matters
The session id exists precisely for the retrospective join on a stalled run — matching the abandoned cycle to waiting_tasks / query_snapshots rows captured by other sweeps. The abandon path is the one place the value is load-bearing, and it is the one place it reads 0.
Likely shape
#2868 captures the id off the open connection as a client property (SqlConnection.ServerProcessId / NpgsqlConnection.ProcessID) rather than querying for it. Candidate causes worth checking rather than assuming: the property being read from a connection object already in a broken/doomed state at abandon time; the value being captured lazily at write time instead of at open; or the provider returning default(int) when the connection has been cancelled. The V109 review already withdrew one over-claim about NULL semantics on this path (budget firing inside ExecuteReaderAsync before the counting reader exists) — this may be the sibling case for the session id, in which case the honest fix could be writing NULL (not-recorded) rather than a literal 0, which reads as a real-looking-but-wrong value.
0 is worse than NULL here: NULL means not-recorded by declared convention; 0 looks like data.
Root cause: the capture sat before `ExecuteReaderAsync`, and `SqlConnection.ServerProcessId` isn't reliably populated until the connection has round-tripped a command — a connection that hadn't yet completed that exchange reported the provider's not-populated 0. The write side also guarded every other forensic figure (`>= 0`) but passed the session id through bare.
Fix: capture moved to after the open round trip (so a drain-stall abandon now records its real id — the case the column was built for), the helper normalizes non-positive values to null at the source, and the writer grows the sibling-shaped `spid > 0` guard.
Verified three ways, each proven red against the unfixed source: a source-order pin (capture must follow `ExecuteReaderAsync`), the helper's normalization, and the writer's guard — plus a behavioral check on the built assembly (a never-opened `SqlConnection` maps to null on the fix, leaked 0 without it). All six PR checks green against the merged head SHA, zero inline review findings.
`Fixes #N` only fires on the dev→main release merge, so closing manually per house policy.
Activity
Merge pull request #2886 from erikdarlingdata/fix/2884-abandon-path-s…
erikdarlingdata commentedon Sep 4, 2026
Fixed by #2886, merged to `dev` as `6b1abf75`.
Root cause: the capture sat before `ExecuteReaderAsync`, and `SqlConnection.ServerProcessId` isn't reliably populated until the connection has round-tripped a command — a connection that hadn't yet completed that exchange reported the provider's not-populated 0. The write side also guarded every other forensic figure (`>= 0`) but passed the session id through bare.
Fix: capture moved to after the open round trip (so a drain-stall abandon now records its real id — the case the column was built for), the helper normalizes non-positive values to null at the source, and the writer grows the sibling-shaped `spid > 0` guard.
Verified three ways, each proven red against the unfixed source: a source-order pin (capture must follow `ExecuteReaderAsync`), the helper's normalization, and the writer's guard — plus a behavioral check on the built assembly (a never-opened `SqlConnection` maps to null on the fix, leaked 0 without it). All six PR checks green against the merged head SHA, zero inline review findings.
`Fixes #N` only fires on the dev→main release merge, so closing manually per house policy.
Capture the target session id after the open round trip, and never wr…