Skip to content

feat: rfc0018.3 green — transient ingest failures map to retryable codes - #270

Merged
jensholdgaard merged 5 commits into
mainfrom
feat/rfc0018-green-retryable
Jun 20, 2026
Merged

feat: rfc0018.3 green — transient ingest failures map to retryable codes#270
jensholdgaard merged 5 commits into
mainfrom
feat/rfc0018-green-retryable

Conversation

@jensholdgaard

@jensholdgaard jensholdgaard commented Jun 20, 2026

Copy link
Copy Markdown
Owner

RFC 0018 green (5/6) — transient ingest failures are retryable (RFC0018.3)

The receiver mapped every non-tenant failure (WAL append/fsync) to gRPC INTERNAL / HTTP 500 — both non-retryable per the OTLP failures table, so a compliant client drops a batch it should retry. A WAL failure is transient (the batch wasn't acked, §3.4); report it retryable (RFC 0018 §3.2):

  • gRPC: WAL failure → UNAVAILABLE (was INTERNAL); tenant failure stays INVALID_ARGUMENT; a panicked ingest task stays INTERNAL.
  • HTTP: WAL failure → 503 (was 500); tenant failure stays 400; panic → 500.

Verification (RFC0018.3, both transports)

tests/rfc0018_retryable.rs: transient (fsync fails) → UNAVAILABLE / 503; permanent (unresolvable tenant) → INVALID_ARGUMENT / 400. Driven by a new FailingSyncJournal in ingest_support (append ok, fsync → WalSync). clippy --all-targets, fmt clean.

RFC 0018: 5 of 6 §5 scenarios green (.1/.2/.3/.4/.6). Remaining: .5 (non-finite doubles — the custom-serde one).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Refined OTLP Logs error mapping for retryability across gRPC and HTTP.
    • Transient WAL append/sync failures now return retryable statuses (gRPC UNAVAILABLE, HTTP 503) instead of treating them as internal errors.
    • Oversized payloads now return non-retryable client errors (gRPC INVALID_ARGUMENT, HTTP 413), while tenant-resolution issues remain permanent client errors.
  • Tests

    • Added/expanded end-to-end compliance scenarios verifying transient vs. permanent mappings for both gRPC and HTTP, including removed ignored stubs.
  • Documentation

    • Updated the OTLP error-mapping RFC0018 guidance to explicitly distinguish oversize payload handling.

The receiver mapped every non-tenant failure (WAL append/fsync) to gRPC
INTERNAL / HTTP 500 — both NON-retryable per the OTLP failures table, so a
compliant client drops a batch it should retry (RFC 0018 §3.2). A WAL
failure is transient (the batch wasn't acked, §3.4); report it retryable:

- gRPC: WAL failure → UNAVAILABLE (was INTERNAL); tenant failure stays
  INVALID_ARGUMENT; a panicked ingest task stays INTERNAL.
- HTTP: WAL failure → 503 (was 500); tenant failure stays 400; panic → 500.

Greens RFC0018.3 in tests/rfc0018_retryable.rs (both transports: transient →
UNAVAILABLE/503, permanent → INVALID_ARGUMENT/400), driven by a new
FailingSyncJournal in ingest_support (append ok, fsync fails → WalSync).
Removed the .3 stub from rfc0018_otlp_compliance.rs.

RFC 0018: 5 of 6 §5 scenarios green (.1/.2/.3/.4/.6). Remaining: .5
(non-finite doubles).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jensholdgaard
jensholdgaard requested a review from Copilot June 20, 2026 20:01
@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jensholdgaard, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 43 minutes and 54 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b4267417-ee8b-4128-a341-fe88d600fee3

📥 Commits

Reviewing files that changed from the base of the PR and between b6192cd and fc64203.

📒 Files selected for processing (4)
  • crates/ourios-ingester/src/receiver/grpc.rs
  • crates/ourios-ingester/src/receiver/http.rs
  • crates/ourios-ingester/src/receiver/tenant.rs
  • docs/rfcs/0018-otlp-log-spec-compliance.md
📝 Walkthrough

Walkthrough

The gRPC and HTTP OTLP receiver handlers are updated to pattern-match ReceiveError and return distinct retryable error codes (Unavailable/503) for transient WAL/fsync failures, non-retryable codes for permanent oversize payloads, and client errors for tenant-resolution failure. Test journal helpers (FailingSyncJournal, FailingAppendJournal) inject failure modes, and new rfc0018_retryable.rs integration tests verify the full mapping across both protocols. RFC 0018 spec is clarified, and the prior ignored stub is removed.

Changes

RFC0018.3 Retryable Error Mapping

Layer / File(s) Summary
gRPC and HTTP receiver error code remapping
crates/ourios-ingester/src/receiver/grpc.rs, crates/ourios-ingester/src/receiver/http.rs
gRPC export handler and HTTP handle_logs now pattern-match ReceiveError to map transient WAL/fsync failures to Status::unavailable and HTTP 503 SERVICE_UNAVAILABLE (retryable), oversize payloads to InvalidArgument and 413 PAYLOAD_TOO_LARGE (permanent), and task panics to Internal and 500 (non-retryable).
Test journal helpers for failure injection
crates/ourios-ingester/tests/ingest_support/mod.rs
Adds FailingSyncJournal (sync always returns ReceiveError::WalSync) and FailingAppendJournal (configurable append failure) with public helpers failing_sync_pipeline(), failing_append_pipeline_transient(), and oversize_append_pipeline() to construct pipelines with specific failure modes.
RFC0018.3 integration tests
crates/ourios-ingester/tests/rfc0018_retryable.rs
New test module with gRPC and HTTP scenario tests asserting transient WAL/fsync and append failures map to Unavailable/503, permanent oversize payloads to InvalidArgument/413, and unresolvable tenants to InvalidArgument/400. Request constructors distinguish resolvable and unresolvable OTLP resources.
RFC spec updates and prior stub removal
docs/rfcs/0018-otlp-log-spec-compliance.md, crates/ourios-ingester/tests/rfc0018_otlp_compliance.rs
RFC 0018 error-mapping contract clarified: transient WAL/storage/saturation failures map to retryable Unavailable/503; permanent oversize payloads (frame batches exceeding 16 MiB) map to non-retryable InvalidArgument/413. Prior ignored RFC0018.3 todo!() stub removed; compliance comment updated to reference new test files.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • jensholdgaard/ourios#134: Introduces the IngestPipeline and ReceiveError variants (WalAppend, WalSync, TenantResolution) that the error code remapping in this PR branches on.
  • jensholdgaard/ourios#265: Specifies the RFC 0018 error-to-status mapping contract that this PR implements in the receiver handlers and verifies in integration tests.
  • jensholdgaard/ourios#266: Added the ignored RFC0018.3 transient-retryable stub in rfc0018_otlp_compliance.rs that this PR removes and replaces with real assertions.

Poem

🐇 A WAL sync trips, the disk says "not now!"
The old code said internal — but that's a broken vow.
With unavailable set, clients know to try again,
And FailingSyncJournal proves we've made the pen.
Tests map transient to 503, permanent to 413—
No more ignored stubs, the RFC dream is clean! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: implementing RFC0018.3 to map transient ingest failures to retryable codes, which is the primary objective of this PR.
Description check ✅ Passed The description covers the problem, solution, verification approach, and testing, and follows the template structure with Summary, Related, and implementation details that align with the objectives.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/rfc0018-green-retryable

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR completes RFC0018.3 by ensuring transient ingest failures (WAL append/sync) are reported as retryable statuses at the transport layer, preventing compliant OTLP clients from incorrectly dropping batches on server-side durability failures.

Changes:

  • Map WAL append/sync failures to gRPC UNAVAILABLE (instead of INTERNAL) in the OTLP/gRPC receiver.
  • Map WAL append/sync failures to HTTP 503 Service Unavailable (instead of 500) in the OTLP/HTTP receiver, while keeping tenant-resolution failures as client errors.
  • Add RFC0018.3 integration tests validating transient vs. permanent failure mappings for both transports, backed by a new failing-fsync test journal.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
crates/ourios-ingester/src/receiver/grpc.rs Change WAL failure mapping to retryable gRPC UNAVAILABLE.
crates/ourios-ingester/src/receiver/http.rs Change WAL failure mapping to retryable HTTP 503; keep tenant failures as 400.
crates/ourios-ingester/tests/ingest_support/mod.rs Add FailingSyncJournal + helper pipeline to inject WAL sync failures in tests.
crates/ourios-ingester/tests/rfc0018_retryable.rs New RFC0018.3 tests asserting retryable vs. permanent failure status mappings (gRPC + HTTP).
crates/ourios-ingester/tests/rfc0018_otlp_compliance.rs Remove the old ignored RFC0018.3 stub and update test-suite documentation pointers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/ourios-ingester/src/receiver/grpc.rs Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comment thread crates/ourios-ingester/src/receiver/grpc.rs Outdated
Copilot: the top-of-file doc still claimed WAL failure → INTERNAL; the
implementation now maps it to UNAVAILABLE (transient, retryable; RFC 0018
§3.2). Update the doc to match, and note the panicked-task → INTERNAL arm.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comment thread crates/ourios-ingester/src/receiver/grpc.rs Outdated
Comment thread crates/ourios-ingester/src/receiver/http.rs Outdated
Copilot: ReceiveError is #[non_exhaustive], so Ok(Err(_)) => retryable would
mark a future non-tenant variant retryable. Match WalAppend/WalSync
explicitly instead. Within ourios-ingester the arms are exhaustive over
ReceiveError (TenantResolution + WalAppend|WalSync), so a catch-all fallback
is unreachable — and a future variant breaks the build here, forcing an
explicit retryable-vs-not decision (stronger than a runtime fallback).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Comment thread crates/ourios-ingester/src/receiver/grpc.rs Outdated
Comment thread crates/ourios-ingester/src/receiver/http.rs Outdated
Comment thread crates/ourios-ingester/tests/rfc0018_retryable.rs Outdated
Copilot: ReceiveError::WalAppend can be AppendError::TooLarge (payload >
16 MiB MAX_FRAME_BYTES) — a client sizing error, not a transient WAL
outage. Mapping it to UNAVAILABLE/503 would make compliant clients retry
the same oversized batch forever. Carve TooLarge out to non-retryable
INVALID_ARGUMENT (gRPC) / 413 (HTTP); other WalAppend/WalSync failures
stay retryable. Add end-to-end coverage for both the transient WalAppend
path and the TooLarge permanent path (FailingAppendJournal). RFC §3.2
permanent-failure bullet updated to name the oversize carve-out.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/ourios-ingester/src/receiver/http.rs`:
- Around line 120-135: The status code mapping logic in the handle_logs function
is non-trivial protocol mapping that currently lacks unit test coverage, relying
only on integration tests. Add a cfg(test) module adjacent to the handle_logs
function that includes unit tests covering the different error scenarios handled
in the match statement: the WalAppend TooLarge case returning PAYLOAD_TOO_LARGE
(413), and the WalAppend and WalSync cases returning SERVICE_UNAVAILABLE (503).
This keeps regression testing local per coding guidelines.

In `@docs/rfcs/0018-otlp-log-spec-compliance.md`:
- Around line 146-151: The RFC mapping text currently groups all permanent
failures under HTTP 413, but the implemented behavior actually maps different
permanent error classes to different HTTP codes. Separate the permanent error
classes explicitly in the text: tenant-resolution failures and malformed
payloads should map to HTTP 400, while oversize payload errors
(AppendError::TooLarge) should map to HTTP 413. Update the bullet point to
clearly distinguish these two classes of permanent errors and their respective
HTTP status codes to align with the current implementation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f1c970a0-9c8c-4a33-ac62-f6f8aaf68bda

📥 Commits

Reviewing files that changed from the base of the PR and between 54c53b4 and b6192cd.

📒 Files selected for processing (5)
  • crates/ourios-ingester/src/receiver/grpc.rs
  • crates/ourios-ingester/src/receiver/http.rs
  • crates/ourios-ingester/tests/ingest_support/mod.rs
  • crates/ourios-ingester/tests/rfc0018_retryable.rs
  • docs/rfcs/0018-otlp-log-spec-compliance.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/ourios-ingester/src/receiver/grpc.rs

Comment thread crates/ourios-ingester/src/receiver/http.rs Outdated
Comment thread docs/rfcs/0018-otlp-log-spec-compliance.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread docs/rfcs/0018-otlp-log-spec-compliance.md Outdated
CodeRabbit/Copilot review:
- Extract the ingest-error → status mapping into pure fns
  (ingest_error_status) in grpc.rs and http.rs, with adjacent #[cfg(test)]
  unit tests covering all variants (tenant→400/INVALID_ARGUMENT, oversize
  TooLarge→413/INVALID_ARGUMENT, append-Io/quiesce/sync→503/UNAVAILABLE).
  Satisfies the crate rule that non-trivial logic carries local unit
  tests, keeping regressions local alongside the end-to-end coverage.
- Fix RFC 0018 §3.2 permanent-failure wording: it read as if all
  permanent failures map to 413; split it into 400 (tenant/malformed) vs
  413 (oversize) to match the implementation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

@jensholdgaard
jensholdgaard merged commit 5504e21 into main Jun 20, 2026
21 checks passed
@jensholdgaard
jensholdgaard deleted the feat/rfc0018-green-retryable branch June 20, 2026 21:32
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.

2 participants