Summary
client_invoke refreshes the core client ID after DesktopSessionExpired, but the superseded core-side client ID is never released. Concurrent refreshes can also race and leave additional replacement IDs unreleased.
Current behavior
In src/client.rs, session refresh does this:
- calls
inner.core.init_client(&inner.config)
- stores the returned ID with
inner.set_client_id(new_id)
- retries the invocation with the new ID
Client::drop later releases only the currently stored ID. Any old or losing replacement IDs can remain allocated in the core/shared library.
Why this matters
- Resource leak risk in the opaque core/shared library.
- Concurrent calls that hit
DesktopSessionExpired can both reinitialize and race to store different IDs.
- A retry can run with an ID that is immediately superseded by another refresh.
Suggested direction
Replace the bare atomic refresh path with serialized lifecycle state, for example:
- add a reinitialization lock or replace
AtomicU64 with a locked client session state
- on
DesktopSessionExpired, re-check whether another thread already refreshed
- reinitialize only when needed
- release the superseded client ID when safe
- ensure
Drop releases the final active ID exactly once
Acceptance criteria
- Superseded client IDs are released when desktop session refresh replaces them.
- Concurrent refreshes do not leak losing replacement IDs.
- Existing retry-on-
DesktopSessionExpired behavior is preserved.
- Unit tests cover single refresh and concurrent/competing refresh behavior with a mock
Core.
cargo fmt --check, cargo clippy --all-features -- -D warnings, and cargo test pass.
Summary
client_invokerefreshes the core client ID afterDesktopSessionExpired, but the superseded core-side client ID is never released. Concurrent refreshes can also race and leave additional replacement IDs unreleased.Current behavior
In
src/client.rs, session refresh does this:inner.core.init_client(&inner.config)inner.set_client_id(new_id)Client::droplater releases only the currently stored ID. Any old or losing replacement IDs can remain allocated in the core/shared library.Why this matters
DesktopSessionExpiredcan both reinitialize and race to store different IDs.Suggested direction
Replace the bare atomic refresh path with serialized lifecycle state, for example:
AtomicU64with a locked client session stateDesktopSessionExpired, re-check whether another thread already refreshedDropreleases the final active ID exactly onceAcceptance criteria
DesktopSessionExpiredbehavior is preserved.Core.cargo fmt --check,cargo clippy --all-features -- -D warnings, andcargo testpass.