You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Analytics shutdown flush is best-effort and can be lost on process exit #58
Following on from #55 / #57, the analytics thread now flushes buffered counts when its last sender drops, but nothing waits for that flush to finish.
We can fix that, however, we need to make design decisions around AnalyticsProcessor lifecycle to find the best place to block at. Right now, AnalyticsProcessor clones owned by Flags can outlive Flagsmith, which is arguably wrong.
Options
Add explicit shutdown() on Flagsmith that closes the channel and joins with a bounded timeout; stop giving Flags an owning clone so the processor's lifetime is tied to Flagsmith alone.
@khvn26, option1 in #58 can have an observable shutdown contract without making Drop block. A proposed state machine is RUNNING → CLOSING → CLOSED: explicit shutdown stops accepting analytics events, drains events accepted before the close boundary, then waits for the final flush/join. One caller-supplied deadline bounds the whole drain+flush/join operation. Flags that outlive the client may still expose their resolved values, but must not keep an owning analytics sender alive or reopen the queue.
Free mock tests: (1) events accepted before close appear exactly once in the drained batch when draining completes; (2) an outliving Flags handle does not delay channel closure; (3) an event racing close is either accepted-before-close or rejected-after-close, never silently counted as flushed; (4) a second shutdown is harmless; (5) deadline expiry returns a distinct incomplete/unknown result with remaining/in-flight counts. Keep queue-drained, request-completed and remote-acknowledged states separate. Even an acknowledgement does not establish exactly-once ingestion unless the endpoint contract does.
Use a fake transport and controllable clock first; no analytics traffic is necessary. This is a proposed lifecycle contract, not a compiled Rust change. AI-assisted technical contribution, reviewed before sharing.
Activity
jankvacek-cell commentedon Sep 8, 2026
@khvn26, option1 in #58 can have an observable shutdown contract without making Drop block. A proposed state machine is RUNNING → CLOSING → CLOSED: explicit shutdown stops accepting analytics events, drains events accepted before the close boundary, then waits for the final flush/join. One caller-supplied deadline bounds the whole drain+flush/join operation. Flags that outlive the client may still expose their resolved values, but must not keep an owning analytics sender alive or reopen the queue.
Free mock tests: (1) events accepted before close appear exactly once in the drained batch when draining completes; (2) an outliving Flags handle does not delay channel closure; (3) an event racing close is either accepted-before-close or rejected-after-close, never silently counted as flushed; (4) a second shutdown is harmless; (5) deadline expiry returns a distinct incomplete/unknown result with remaining/in-flight counts. Keep queue-drained, request-completed and remote-acknowledged states separate. Even an acknowledgement does not establish exactly-once ingestion unless the endpoint contract does.
Use a fake transport and controllable clock first; no analytics traffic is necessary. This is a proposed lifecycle contract, not a compiled Rust change. AI-assisted technical contribution, reviewed before sharing.