-
-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Background
In Issue #12, we introduced lifecycle state tracking via SafeBoxStateListener
and SafeBoxGlobalStateObserver
to monitor SafeBox transitions (STARTING
, WRITING
, IDLE
, CLOSED
). Initially, state emissions were performed directly inside SafeBoxBlobStore
, tied to internal write completions.
We also added .closeWhenIdle()
to allow SafeBox instances to defer closure until all writes were done. However, this approach had critical timing limitations.
Problem
The original definition of WRITING
and IDLE
was too granular. SafeBoxBlobStore
emitted IDLE
after each individual blob write, but this didn’t reflect the actual lifecycle of an edit()
or commit()
operation at the SafeBox
level.
Consider:
safeBox.edit {
putString("key1", "value1")
putInt("key2", 2)
}
safeBox.closeWhenIdle()
The flaw:
- Each
.edit()
launches a coroutine that may perform multiple blob writes. SafeBoxBlobStore
emitsIDLE
as soon as one write finishes.- Meanwhile,
.closeWhenIdle()
may observe this prematureIDLE
and begin closing. - This can result in
WRITING
being emitted afterCLOSED
, leading to race conditions and invalid state flows.
Final Solution
We replaced all write-level state emission logic with a centralized lifecycle coordinator:
✅ SafeBoxStateManager
This internal component:
- Tracks concurrent edits via atomic counters
- Emits:
STARTING
during initial readWRITING
once when the first edit beginsIDLE
only when all edits completeCLOSED
aftercloseWhenIdle()
or manual closure
- Ensures deterministic transitions, even under rapid
.apply()
/.commit()
usage - Fully decouples lifecycle concerns from
SafeBoxBlobStore
Implementation Highlights
- All lifecycle events now originate from
SafeBoxStateManager
SafeBox
useslaunchCommitWithWritingState
andlaunchApplyWithWritingState
to delegate state-aware operationswriteCompleted
is tracked viaCompletableDeferred
to blockcloseWhenIdle()
until all writes settle- Test coverage added to verify transition order:
STARTING → WRITING → IDLE → CLOSED
- Manual loop in test uses
Thread.sleep(3)
for CPU-friendly polling
Benefits
- No more premature
IDLE
emissions - Guaranteed
CLOSED
only after finalWRITING
ends - Supports aggressive async edits without race
- Clear mental model: states represent full
SafeBox
lifecycle - Simplifies future debugging, instrumentation, and test hooks
Related Issues
- Add
SafeBoxGlobalStateObserver
to Support Runtime Lifecycle Monitoring #12 (Initial lifecycle state implementation)
Sub-issues
Metadata
Metadata
Assignees
Labels
Projects
Status