Skip to content

Count pipeline errors per-command, not per-window - #124

Closed
fcostaoliveira wants to merge 1 commit into
fix/optin-reply-capture-117from
fix/pipeline-error-count-118
Closed

Count pipeline errors per-command, not per-window#124
fcostaoliveira wants to merge 1 commit into
fix/optin-reply-capture-117from
fix/pipeline-error-count-118

Conversation

@fcostaoliveira

Copy link
Copy Markdown
Contributor

Closes #118.

Stacked on #123 (#117). Base is fix/optin-reply-capture-117 so the diff is clean; it retargets to master automatically once #123 merges. Review/merge #123 first.

Problem

radix.Pipeline.Run stops decoding at the first failing command, drains (discards) the remaining replies, and returns a single aggregate error for the whole batch. flushPending then marked every command in the pipeline window as errored — so one bad reply (e.g. a WRONGTYPE) in a window of N inflated the error count by up to N.

Fix

Replace radix.Pipeline with a small custom Action (pipelineErrs) that:

  • still sends the whole batch in one buffered write (via multiMarshal) — pipelining is preserved;
  • decodes every reply and records each command's own error in errs[i] instead of draining.

flushPending now attributes hadError/isTimeout per command:

  • a RESP error (WRONGTYPE/OOM) fails only its own command;
  • a transport error (i/o timeout) fails that command and the ones after it (the connection is broken), while already-decoded commands stay successful.

Read cost is unchanged — radix.Pipeline also decodes/drains all N replies. Everything is built on public radix interfaces (CmdAction embeds resp.Marshaler/resp.Unmarshaler; Conn.Encode/Decode), no internal-type assertions.

Validation

TestFTSBPipelineErrorCountedPerCommandNotPerWindow: one WRONGTYPE among 9 good HSETs in a pipeline of 10 (--workers 1, deterministic) → asserts Errors == 1.

Negative control — same input, pre-fix binary: TotalOps=20 Errors=10. Fixed binary: Errors=1. Existing error/timeout integration tests still pass; unit suite green under -race.

radix.Pipeline.Run stops decoding at the first failing command, drains
(discards) the remaining replies, and returns a single aggregate error for the
whole batch. flushPending then marked EVERY command in the pipeline window as
errored, so one bad reply (e.g. a WRONGTYPE) in a window of N inflated the error
count by up to N.

Replace radix.Pipeline with a small custom Action (pipelineErrs) that still
sends the whole batch in one buffered write (via multiMarshal) but decodes every
reply and records each command's own error in errs[i]. flushPending now
attributes hadError/isTimeout per command from that slice: a RESP error fails
only its own command; a transport error (i/o timeout) fails that command and the
ones after it (the connection is broken) while the already-decoded ones stay
successful. The read cost is unchanged -- radix.Pipeline also decodes/drains all
N replies.

Regression guard: TestFTSBPipelineErrorCountedPerCommandNotPerWindow feeds one
WRONGTYPE among 9 good HSETs in a pipeline of 10 (workers=1, deterministic) and
asserts Errors==1. Verified the pre-fix binary reports Errors==10 for the same
input. Existing error/timeout integration tests still pass.
@sonarqubecloud

Copy link
Copy Markdown

@fcostaoliveira
fcostaoliveira deleted the branch fix/optin-reply-capture-117 July 13, 2026 21:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant