Skip to content

fix(events): succeed on the event endpoint's reply and send each queued event once - #16

Merged
onamfc merged 1 commit into
mainfrom
fix/event-response
Oct 21, 2026
Merged

onamfc merged 1 commit into
mainfrom
fix/event-response

Conversation

@onamfc

@onamfc onamfc commented Oct 21, 2026

Copy link
Copy Markdown
Member

Summary

POST /api/sdk/v1/event replies {"eventId": "...", "acknowledged": true}. EventResponse required a success field the endpoint has never sent, so json['success'] as bool threw on every reply. The result, for every trackEvent, trackRevenue and trackScreenView:

  1. the server stored the event;
  2. the SDK threw a DecodingError to the app, queued the event and persisted the queue;
  3. each flushQueue() sent the head of the queue again (stored again, failed to decode again, re-queued at the tail), and the persisted queue carried the events into later launches.

Changes

  • EventResponse reads eventId and acknowledged, both optional, so any 2xx reply decodes. It isn't exported, so no public API changes.
  • An event is queued only when it may succeed later: a NetworkError, or an InvalidResponseError with no status or a 5xx. A 4xx is thrown and not queued.
  • flushQueue(): a queued event that fails with a retryable error goes back to the head of the queue (EventQueue.requeueFront) and the flush stops; one the server rejects is dropped and the flush continues. Events used to go back to the tail, reordering the queue.
  • Version 0.3.2: pubspec.yaml, SdkInfo.version, CHANGELOG, README pin, example lockfile.

Events already persisted on a device by earlier versions are sent once more on the next flush and then leave the queue.

Tests

  • New test/events/event_server_contract_test.dart runs EventTracker over the real NetworkManager and EventQueue, answered in the server's reply shapes: trackEvent succeeds and queues nothing; a flush sends each queued event once; a still-failing event keeps its place; a 4xx is not queued; a rejected queued event is dropped and the rest are sent. All 5 fail against the previous code.
  • event_response_test.dart decodes the real reply and an empty one. Event tracker mocks use the real reply shape.
  • flutter test: 148 passed. flutter analyze: no issues. dart format: clean. build_runner output committed.

The same decoding bug was fixed in the iOS (1.5.0) and Android (1.4.0) SDKs.

…ed event once

The event endpoint replies {eventId, acknowledged}; EventResponse required
a success field, so every trackEvent threw a DecodingError after the
event was stored, queued it, and sent it again on each flush and, from
the persisted queue, on later launches. EventResponse reads the real
reply with both fields optional.

An event is queued only after a network error or a 5xx. A queued event
the server rejects is dropped, and one that fails again goes back to the
head of the queue, so events keep their order. Version 0.3.2.
@onamfc
onamfc merged commit 214eb32 into main Oct 21, 2026
4 checks passed
@onamfc
onamfc deleted the fix/event-response branch October 21, 2026 03:23
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