Skip to content

fix(replay): split uploads at session and identity boundaries - #836

Open
dustinbyrne wants to merge 1 commit into
mainfrom
fix/replay-batch-attribution
Open

dustinbyrne wants to merge 1 commit into
mainfrom
fix/replay-batch-attribution

Conversation

@dustinbyrne

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

Replay ingestion attributes an entire /s/ request to its first snapshot's session and distinct ID. Android's persisted replay queue could batch snapshots across those boundaries, filing a new session's opening frames under the preceding session after an app restart.

This ports the batching fix released in posthog-ios 3.88.2:

  • Split replay requests when either the session ID or distinct ID changes.
  • Send contiguous groups sequentially within the original count-limited flush window, preserving FIFO.
  • Delete only completed or terminally rejected groups; retain a retryable failed group and all unsent groups.
  • Keep analytics/log batching, public APIs, and configuration defaults unchanged.

This preserves the existing event-batcher specification and implements the replay-attribution contract proposed in sdk-specs #92, which is still open. Patch changesets cover posthog and posthog-android.

💚 How did you test it?

Local validation with JDK 17:

  • Added 10 wire-level queue tests using MockWebServer, including session/identity boundaries, persisted restart, count limits, threshold flushes, retry retention, terminal errors, HTTP 413, corrupt records, and unchanged analytics batching. Eight boundary tests fail on the unchanged base; all ten pass with the fix.
  • make testJava: all 1,022 core tests passed.
  • make checkFormat: passed.
  • ./gradlew :posthog:apiCheck :posthog-android:apiCheck :posthog-android:compileReleaseKotlin: passed.
  • Fresh read-only independent review: no findings.

Validation is at the queue/HTTP layer. Android device kill/relaunch and Cloud ingestion/playback have not been tested.

📝 Checklist

  • Reviewed the submitted code.
  • Added regression tests.
  • No public API or configuration-default changes.
  • Added patch changesets for the core and Android packages.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Pi implemented the Android port, with a fresh read-only reviewer agent checking the diff, callers, retry/lifecycle behavior, and tests. Tools used: read, edit, write, bash, and subagent. The implementation keeps replay attribution policy in the existing endpoint specification and reuses the shared durable queue and retry handling.

@dustinbyrne dustinbyrne self-assigned this Oct 3, 2026
@greptile-apps

greptile-apps Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Retrigger

[Medium risk] Changes how session replay batches are split and sent.

The PR appears safe to merge; no actionable issues were found.

Reviews (1) · Last reviewed commit: "fix(replay): split uploads at session an..."

@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

posthog-android Compliance Report

Date: 2026-10-03 02:12:49 UTC
Duration: 117774ms

✅ All Tests Passed!

46/46 tests passed


Capture Tests

✅ 29/29 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 245ms
Format Validation.Event Has Uuid ✅ 19ms
Format Validation.Event Has Lib Properties ✅ 21ms
Format Validation.Distinct Id Is String ✅ 17ms
Format Validation.Token Is Present ✅ 17ms
Format Validation.Custom Properties Preserved ✅ 16ms
Format Validation.Event Has Timestamp ✅ 19ms
Retry Behavior.Retries On 503 ✅ 7022ms
Retry Behavior.Does Not Retry On 400 ✅ 4017ms
Retry Behavior.Does Not Retry On 401 ✅ 4018ms
Retry Behavior.Respects Retry After Header ✅ 7022ms
Retry Behavior.Implements Backoff ✅ 17030ms
Retry Behavior.Retries On 500 ✅ 7017ms
Retry Behavior.Retries On 502 ✅ 7016ms
Retry Behavior.Retries On 504 ✅ 7017ms
Retry Behavior.Max Retries Respected ✅ 17019ms
Deduplication.Generates Unique Uuids ✅ 40ms
Deduplication.Preserves Uuid On Retry ✅ 7012ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 12017ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 7017ms
Deduplication.No Duplicate Events In Batch ✅ 25ms
Deduplication.Different Events Have Different Uuids ✅ 16ms
Compression.Sends Gzip When Enabled ✅ 11ms
Batch Format.Uses Proper Batch Structure ✅ 11ms
Batch Format.Flush With No Events Sends Nothing ✅ 8ms
Batch Format.Multiple Events Batched Together ✅ 23ms
Error Handling.Does Not Retry On 403 ✅ 4016ms
Error Handling.Does Not Retry On 413 ✅ 4013ms
Error Handling.Retries On 408 ✅ 5020ms

Feature_Flags Tests

✅ 17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 22ms
Request Payload.Flags Request Uses V2 Query Param ✅ 15ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 17ms
Request Payload.Flags Request Omits Authorization Header ✅ 15ms
Request Payload.Token In Flags Body Matches Init ✅ 14ms
Request Payload.Groups Round Trip ✅ 16ms
Request Payload.Groups Default To Empty Object ✅ 18ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 25ms
Request Payload.Disable Geoip Omitted Defaults To False ✅ 15ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 15ms
Request Lifecycle.No Flags Request On Init Alone ✅ 5ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 12ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 26ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 12ms
Retry Behavior.Retries Flags On 502 ✅ 313ms
Retry Behavior.Retries Flags On 504 ✅ 315ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 14ms

@dustinbyrne
dustinbyrne marked this pull request as ready for review October 3, 2026 16:16
@dustinbyrne
dustinbyrne requested a review from a team as a code owner October 3, 2026 16:16

This branch has not been deployed

No deployments
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