Skip to content

feat(sync): let a producer report whether a publish can still land - #236

Merged
lxsaah merged 2 commits into
mainfrom
feat/sync-producer-check
Aug 27, 2026
Merged

feat(sync): let a producer report whether a publish can still land#236
lxsaah merged 2 commits into
mainfrom
feat/sync-producer-check

Conversation

@lxsaah

@lxsaah lxsaah commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Why

A facade built on aimdb-sync has to answer "can I still publish?" for its own callers, and today it cannot.

fork::generation and fork::forked_since are crate-private, and asking the AimDbHandle is not open to an FFI door that keeps it behind a lock — answering while a shutdown holds that lock is exactly how a caller's interpreter lock deadlocks against its own teardown. That is the lock-ordering rule the Python door established.

So the question had no supported route. aimdb-weather-mesh's StationHandle::is_closed reached for aimdb_sync::fork::* instead, and stopped compiling when #235 made the module private.

What

One method on SyncProducer:

pub fn check(&self) -> SyncResult<()> {
    self.runtime()?.check()
}

Two lines, because #235 had already put every route in behind a single check. Ok(()), or RuntimeShutdown / ForkedChild.

It answers from the one component reachable without the handle's lock — which is also why a publish never queues behind a shutdown. And it is the check set() already performs, not a second one beside it, so it cannot report open while a publish would be refused.

On exposing fork instead

Not done, deliberately. What this commits to in semver is the question, not the mechanism. Publishing the generation pair would pin stamp-and-compare — the objection 2bcc5a3 raised when it withdrew them mid-PR.

That commit deferred the decision for want of a real caller to design against. The caller exists now, and its requirement is specific: cheap, and never the mutex. check() is designed against it. The note on fork::generation claiming no such layer exists is corrected to point at the supported route.

Tests

  • check_reports_what_a_publish_would_find — usable while attached, RuntimeShutdown after detach, and the same verdict set() reaches.
  • The forked-child test now also asserts check() agrees with the two publishes beside it. That agreement is the property a facade depends on.

Verification

  • aimdb-sync: 58 tests green (was 57), plus --no-default-features and --features data-contracts.
  • cargo fmt --check and clippy clean on all three feature configurations.
  • End-to-end through the C++ door in aimdb-weather-mesh (make spike-cpp), all four checks of the fork round green.

Merge order

aimdb-dev/aimdb-weather-mesh has a companion PR that consumes this. This one lands first — that one does not compile without it.

🤖 Generated with Claude Code

A facade built on this crate has to answer "can I still publish?" for its own
callers, and could not. `fork::generation` and `fork::forked_since` are
crate-private, and asking the `AimDbHandle` is not open to an FFI door that
keeps it behind a lock: answering while a shutdown holds that lock is how a
caller's interpreter lock deadlocks against its own teardown.

`SyncProducer::check()` answers it from the one component reachable without that
lock, which is also why a publish never queues behind a shutdown. The body is
`self.runtime()?.check()` — the check `set()` already performs, so this cannot
report open while a publish would be refused. Two lines, because #235 had
already put every route in behind a single check.

What this commits to in semver is the question, not the mechanism. Exposing the
generation pair instead would pin stamp-and-compare, which is the objection
2bcc5a3 raised when it withdrew them. The caller it wanted to design against
now exists — weather-station's `StationHandle::is_closed` — and its requirement
is specific: cheap, and never the mutex.

The note on `fork::generation` claiming no such layer exists is corrected to
point at the supported route.

Tests: `check_reports_what_a_publish_would_find` covers the attached and
detached arms. The forked-child test now asserts `check()` agrees with the two
publishes beside it, which is the property a facade depends on.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The method is two lines; the doc comment, changelog entry and test comments
around it were not. Each said the same thing three ways — that a facade
cannot ask the handle because its shutdown holds the lock, and that
publishing the generation pair would pin stamp-and-compare in semver. Kept
one statement of each, at the place it belongs, and dropped the retellings.

No behaviour change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GJYfHcnx2CSjmfKDrtoYCA
@lxsaah
lxsaah merged commit ff67837 into main Aug 27, 2026
6 checks passed
@lxsaah
lxsaah deleted the feat/sync-producer-check branch August 27, 2026 18:58
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