Skip to content

axiom: DatasetsService.Ingest silently bypasses retry loop for non-seekable readers #427

Description

The retry loop in Client.Do (axiom/client.go:259) is gated on req.GetBody != nil && !c.noRetry. DatasetsService.Ingest(ctx, id, r io.Reader, ...) at axiom/datasets.go:404 passes its caller-supplied io.Reader directly to NewRequest, which means req.GetBody is only auto-populated by the stdlib when the reader is one of *bytes.Buffer, *bytes.Reader, or *strings.Reader.

For any other reader (the common case for streaming ingest), the retry loop is silently skipped entirely, so transient network errors produce immediate failures with no recovery attempt.

Impact

  • Public API (Ingest) behaves inconsistently with IngestEvents and IngestChannel, both of which explicitly set req.GetBody and therefore do retry on transient failures.
  • Callers have no way to know their reader-based ingest is non-retrying without reading the source.

Options

  1. Document as non-retrying. Update the Ingest godoc to explicitly state that streaming reader bodies are not retried and callers should handle transient failures themselves. Simplest and most honest.
  2. Buffer small readers into memory and synthesize a GetBody function from the buffered bytes. Needs a size threshold to avoid OOMs on large streams. Most user-friendly.
  3. Require callers to provide a reset hook. Add an optional helper (e.g. ingest.WithResettableBody(f func() io.Reader)) that wires into req.GetBody. Most explicit.

Worth discussing trade-offs in comments before implementing.

Same bug class as the body-reset issue fixed in #425, different code path. Surfaced while reviewing that PR.

Related: #425.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions