Skip to content

feat: Retry event delivery and flush on close - #282

Closed
flagsmithsmith[bot] wants to merge 4 commits into
mainfrom
openhands/sdk-spec-v0.8.0
Closed

flagsmithsmith[bot] wants to merge 4 commits into
mainfrom
openhands/sdk-spec-v0.8.0

Conversation

@flagsmithsmith

Copy link
Copy Markdown
Contributor

Contributes to Flagsmith/sdk-spec#23

renovate Bot and others added 2 commits November 11, 2026 12:09
Its entry in Flagsmith/sdk-spec's compatibility matrix at v0.8.0: `core or events or local-evaluation`.
@flagsmithsmith flagsmithsmith Bot added the sdk-spec Bumps of the Flagsmith SDK behavioural spec label Nov 11, 2026
@coderabbitai

coderabbitai Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 44265a80-dee7-4de0-a47e-b85cfcfc6d8e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@codspeed

codspeed Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 15 untouched benchmarks


Comparing openhands/sdk-spec-v0.8.0 (ca330ed) with main (b480743)

Open in CodSpeed

Event delivery now survives transient failures of the events API, as
SDK spec v0.8.0 requires:

- A batch is sent up to 3 times with a 3 s request timeout, backing off
  from 1 s, doubling, with full jitter, one batch in flight at a time.
- A batch whose last attempt fails transiently is kept for the next
  flush, ahead of newer events, unless that attempt got a 500.
- A batch the events API rejects is dropped, and a 401/403 stops event
  tracking.
- A full buffer drops its oldest event.

`Flagsmith.flush_events()` sends the tracked events and waits for the
outcome, and `Flagsmith.close(timeout_seconds)` stops background work
and sends the buffered events within the timeout.

The spec steps file wires the new steps, and a client with both local
evaluation and events.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@flagsmithsmith

Copy link
Copy Markdown
Contributor Author

Implemented SDK spec v0.8.0 in d019e76. The spec job failed because the SDK was missing four steps, and the event delivery behaviour behind them.

SDK changes

  • Retries: event batches are retried on transient failures (5xx, 408, 429, connection errors, timeouts). There are up to 3 attempts with a 3 s request timeout and a full-jitter backoff starting at 1 s and doubling. Only one batch is in flight at a time.
  • After the last attempt: if it failed transiently, the batch is kept for the next flush and sent ahead of newer events. If it got a 500, the batch is dropped. A 400-class rejection drops the batch. A 401/403 stops event tracking.
  • Full buffer: the oldest event is now dropped. Before, re-queued events were truncated from the newest.
  • New Flagsmith.flush_events(): sends the tracked events synchronously and returns once they are delivered, dropped or kept. If another batch was in flight, events it already attempted are not sent again. This matters for the full-buffer scenario, where reaching max_buffer_items starts a background flush.
  • New Flagsmith.close(timeout_seconds=5): stops polling and streaming, then sends the buffered events, returning within the timeout. __del__ and the atexit hook use the same path.

Spec wiring (sdk-spec/steps.py): added Create the SDK client with local evaluation and events enabled, tracks events "event_{first}" to "event_{last}", flushes events and closes the client with a timeout of {timeout} seconds. Each one only calls the SDK.

Verification: I ran the spec v0.8.0 locally with tags core or events or local-evaluation: 24 passed. Unit tests (392) pass, as do mypy --strict . and pre-commit. The new delivery tests mock the events API with responses.

A timer flush running while the client closed scheduled another one, so
the client kept flushing after `close()`.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@flagsmithsmith

Copy link
Copy Markdown
Contributor Author

Unit tests failed on 3.10/3.12/3.13 (the spec job passed). test_stop__sends_buffered_events checked that the timer's thread was no longer alive, but Timer.cancel() only signals it, so the thread can outlive stop() briefly. The test now checks that the timer is cancelled. Looking into it also showed a real race: a timer flush running while the client closed would schedule another timer, so the client kept flushing after close(). Stopping now prevents any further timer flushes, with a test. Fixed in ca330ed.

@flagsmithsmith
flagsmithsmith Bot marked this pull request as ready for review November 11, 2026 13:36
@flagsmithsmith
flagsmithsmith Bot requested a review from a team as a code owner November 11, 2026 13:36
@flagsmithsmith
flagsmithsmith Bot requested review from khvn26 and removed request for a team November 11, 2026 13:36
@flagsmithsmith

Copy link
Copy Markdown
Contributor Author

Superseded by #283, which carries this pull request's work over to the SDK spec's latest version.

@flagsmithsmith flagsmithsmith Bot closed this Nov 11, 2026
@flagsmithsmith
flagsmithsmith Bot deleted the openhands/sdk-spec-v0.8.0 branch November 11, 2026 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sdk-spec Bumps of the Flagsmith SDK behavioural spec

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants