Skip to content

feat(ci): cap gzipped junit upload at 10 MiB and split oversized reports#1722

Merged
mergify[bot] merged 1 commit into
mainfrom
devs/sileht/mrgfy-8050-junit-upload-split-10mib/cap-gzipped-junit-upload-10-mib-split-oversized--acd21260
Jul 20, 2026
Merged

feat(ci): cap gzipped junit upload at 10 MiB and split oversized reports#1722
mergify[bot] merged 1 commit into
mainfrom
devs/sileht/mrgfy-8050-junit-upload-split-10mib/cap-gzipped-junit-upload-10-mib-split-oversized--acd21260

Conversation

@sileht

@sileht sileht commented Jul 17, 2026

Copy link
Copy Markdown
Member

mergify ci junit-process builds every parsed JUnit report into one OTLP
ExportTraceServiceRequest, gzips it, and POSTs it in a single request. A
large report (tens of thousands of cases, or a few with huge stack traces)
can gzip past what the ingest endpoint accepts, and the whole upload is lost.

Cap the compressed body at a named constant MAX_GZIPPED_UPLOAD_BYTES
(10 MiB) and split an oversized payload into several uploads that each gzip
under the cap. The cap is on the gzipped bytes actually sent, not the raw
XML or the uncompressed protobuf: gzip ratios swing wildly between a run of
short case names and one of megabyte stack traces, so only the compressed
size is meaningful. A normal report stays a single upload, byte-identical to
before.

How the split works (new junit_process::split):

  • Decompose the built request into its session / suite / case spans, then
    recursively halve the case list — by encoded size, so one giant case is
    isolated fast — verifying each candidate chunk with an actual gzip.
  • Each chunk is a self-contained trace: the session span, the suite spans for
    the cases it carries, and those cases. Every chunk keeps the original
    trace_id and span_ids, so the backend reassembles one trace from N uploads.
  • Each chunk carries the gzipped bytes it was sized against, so the upload
    step posts them directly instead of compressing a second time.

Oversize single case (one test whose trace alone exceeds the cap gzipped):
skip-and-warn. There is no upload it can fit into, so it is dropped and
listed in the report under "Some test results were too large to upload". The
CI verdict is unaffected — it is computed from the parsed cases, not the
upload — so no test's blocking status is lost, only its telemetry.

Upload semantics: a transient failure on one chunk does not abandon the
rest (each chunk is a self-contained, idempotent trace, so delivering as
many as possible is best), but a permanent rejection stops the loop. When
nothing reaches ingest (every case oversized, or gzip fails) the run reports
test_results_upload=failed rather than a false success, and dropped oversize
cases emit a GitHub Actions warning naming them.

Backend support: the split relies on the ingest endpoint accepting several
same-test_run_id uploads and merging them additively/idempotently by
(trace_id, span_id). That landed in monorepo #36926 (MRGFY-8051); without it
the backend would drop every chunk after the first. This CLI change is inert
until that backend is deployed.

Fixes MRGFY-8050

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

Copilot AI review requested due to automatic review settings July 17, 2026 14:04
@mergify
mergify Bot had a problem deploying to Mergify Merge Protections July 17, 2026 14:04 Failure
@sileht
sileht temporarily deployed to func-tests-live July 17, 2026 14:04 — with GitHub Actions Inactive
@mergify

mergify Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🟢 All 6 merge protections satisfied — ready to merge.

Show 6 satisfied protections

🟢 🤖 Continuous Integration

  • all of:
    • check-success=ci-gate

🟢 👀 Review Requirements

  • any of:
    • #approved-reviews-by>=2
    • author = dependabot[bot]
    • author = mergify-ci-bot
    • author = renovate[bot]

🟢 Enforce conventional commit

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|internal|docs|style|refactor|perf|test|build|ci|chore|revert|ui)(?:\(.+\))?!?:

🟢 🔎 Reviews

  • #changes-requested-reviews-by = 0
  • #review-requested = 0
  • #review-threads-unresolved = 0

🟢 📕 PR description

  • body ~= (?ms:.{48,})

🟢 🚦 Auto-queue

When all merge protections are satisfied, this pull request will be queued automatically.

Copilot AI 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.

Pull request overview

This PR updates mergify ci junit-process to avoid losing the entire OTLP trace upload when a large JUnit run produces a gzipped payload that exceeds the ingest endpoint’s size limit, by introducing a 10 MiB gzipped cap and splitting oversized traces into multiple under-cap uploads.

Changes:

  • Introduces MAX_GZIPPED_UPLOAD_BYTES (10 MiB) and a new split module that partitions oversized ExportTraceServiceRequests into multiple gzipped chunks.
  • Adds upload_compressed so split chunks can be POSTed without re-gzipping.
  • Updates the junit-process command to upload multiple chunks, report dropped oversized single cases, and refine the test_results_upload GitHub output status.

Reviewed changes

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

Show a summary per file
File Description
crates/mergify-ci/src/testing.rs Adds an “incompressible” test helper for reliably forcing gzip-size-based split behavior in tests.
crates/mergify-ci/src/junit_process/upload.rs Adds the gzipped upload size cap constant, exposes gzip internally, and adds upload_compressed for pre-gzipped payloads.
crates/mergify-ci/src/junit_process/split.rs New module implementing recursive split-by-encoded-size with exact gzip verification, plus unit tests.
crates/mergify-ci/src/junit_process/mod.rs Exposes the new split API and re-exports the cap and new upload helper.
crates/mergify-ci/src/junit_process/command.rs Integrates splitting + multi-upload, adds reporting for oversized cases and “nothing uploaded” status handling, and adds end-to-end tests.

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

Comment thread crates/mergify-ci/src/testing.rs
Comment thread crates/mergify-ci/src/junit_process/command.rs Outdated
Comment thread crates/mergify-ci/src/junit_process/command.rs
@mergify
mergify Bot requested a review from a team July 17, 2026 14:10
`mergify ci junit-process` builds every parsed JUnit report into one OTLP
`ExportTraceServiceRequest`, gzips it, and POSTs it in a single request. A
large report (tens of thousands of cases, or a few with huge stack traces)
can gzip past what the ingest endpoint accepts, and the whole upload is lost.

Cap the compressed body at a named constant `MAX_GZIPPED_UPLOAD_BYTES`
(10 MiB) and split an oversized payload into several uploads that each gzip
under the cap. The cap is on the *gzipped* bytes actually sent, not the raw
XML or the uncompressed protobuf: gzip ratios swing wildly between a run of
short case names and one of megabyte stack traces, so only the compressed
size is meaningful. A normal report stays a single upload, byte-identical to
before.

How the split works (new `junit_process::split`):

- Decompose the built request into its session / suite / case spans, then
  recursively halve the case list — by encoded size, so one giant case is
  isolated fast — verifying each candidate chunk with an actual gzip.
- Each chunk is a self-contained trace: the session span, the suite spans for
  the cases it carries, and those cases. Every chunk keeps the original
  trace_id and span_ids, so the backend reassembles one trace from N uploads.
- Each chunk carries the gzipped bytes it was sized against, so the upload
  step posts them directly instead of compressing a second time.

Oversize single case (one test whose trace alone exceeds the cap gzipped):
skip-and-warn. There is no upload it can fit into, so it is dropped and
listed in the report under "Some test results were too large to upload". The
CI verdict is unaffected — it is computed from the parsed cases, not the
upload — so no test's blocking status is lost, only its telemetry.

Upload semantics: a transient failure on one chunk does not abandon the
rest (each chunk is a self-contained, idempotent trace, so delivering as
many as possible is best), but a permanent rejection stops the loop. When
nothing reaches ingest (every case oversized, or gzip fails) the run reports
test_results_upload=failed rather than a false success, and dropped oversize
cases emit a GitHub Actions warning naming them.

Backend support: the split relies on the ingest endpoint accepting several
same-test_run_id uploads and merging them additively/idempotently by
(trace_id, span_id). That landed in monorepo #36926 (MRGFY-8051); without it
the backend would drop every chunk after the first. This CLI change is inert
until that backend is deployed.

Fixes MRGFY-8050

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Change-Id: Iacd21260a73b5e249e32a88f931cd95a7a8ff57a
@sileht
sileht force-pushed the devs/sileht/mrgfy-8050-junit-upload-split-10mib/cap-gzipped-junit-upload-10-mib-split-oversized--acd21260 branch from befe5c7 to cbd9711 Compare July 17, 2026 14:23
@sileht

sileht commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

Revision history

# Type Changes Reason Date
1 initial befe5c7 2026-07-17 14:23 UTC
2 content befe5c7 → cbd9711 (raw) 2026-07-17 14:23 UTC

@sileht
sileht temporarily deployed to func-tests-live July 17, 2026 14:23 — with GitHub Actions Inactive
@mergify
mergify Bot deployed to Mergify Merge Protections July 17, 2026 14:23 Active
@sileht
sileht marked this pull request as ready for review July 17, 2026 15:42
@mergify
mergify Bot requested a review from a team July 18, 2026 05:50
@mergify

mergify Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

This pull request spent 7 minutes 14 seconds in the queue, including 6 minutes 57 seconds running CI.

Required conditions to merge

@mergify mergify Bot added the queued label Jul 20, 2026
@mergify
mergify Bot merged commit 7bb3081 into main Jul 20, 2026
22 of 42 checks passed
@mergify
mergify Bot deleted the devs/sileht/mrgfy-8050-junit-upload-split-10mib/cap-gzipped-junit-upload-10-mib-split-oversized--acd21260 branch July 20, 2026 07:55
@mergify mergify Bot removed the queued label Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants