Skip to content

edge: D2D parity for peer lifecycle @on handlers (on top of #27)#31

Merged
kavya-chennoju merged 1 commit into
feat/peer-lifecycle-eventsfrom
sourav/peer-lifecycle-d2d
May 12, 2026
Merged

edge: D2D parity for peer lifecycle @on handlers (on top of #27)#31
kavya-chennoju merged 1 commit into
feat/peer-lifecycle-eventsfrom
sourav/peer-lifecycle-d2d

Conversation

@soupat
Copy link
Copy Markdown
Collaborator

@soupat soupat commented May 12, 2026

Stacked on #27. Extends peer lifecycle subscriptions to D2D mode.

What changes

#27 routes `@on(event_name="peer_present"|"peer_lost")` to the registry-published `device-connect..device.{online,offline}` subject. D2D mode has no registry publishing those subjects, so D2D drivers using the same decorator see nothing.

This PR delivers the same logical events via `PresenceCollector` callbacks when a D2D collector is present on the device runtime. The `@on` surface, alias names, and `device_id=` filter (exact + glob) are unchanged -- mode-transparent behavior.

How

`discovery.py`:

  • `PresenceCollector` grows symmetric `on_peer_removed` support (fires on `departing: true` graceful departure AND on prune-timeout in `_prune_loop`).
  • Multi-listener model: constructor-form `on_new_peer` / `on_peer_removed` kwargs still work as single-listener seeds; new `add_on_new_peer` / `add_on_peer_removed` methods append additional listeners. The existing `collector._on_new_peer = ...` pattern in `device.py` keeps working via a back-compat property.

`drivers/base.py`:

  • `_setup_subscription` checks `self._device._d2d_collector` for lifecycle aliases; if present, the handler is wired via the collector's new listener methods (`_setup_lifecycle_d2d`) instead of subscribing to the broker subject.
  • Per-device events are unaffected; still subscribe through the broker.

Glob and exact `device_id=` filters apply post-hoc inside the delivery wrapper (same `_device_id_matches` helper as #27).

Tests

9 new tests, 437 total passing (30 from #27 + 7 prior lifecycle + new):

```
TestLifecycleSubscriptionsD2D
test_peer_lost_routes_through_collector
test_peer_present_routes_through_collector
test_d2d_lifecycle_device_id_filter_exact
test_d2d_lifecycle_device_id_filter_glob
test_d2d_per_device_event_still_uses_broker

TestPresenceCollectorRemovedCallback
test_graceful_departure_fires_on_peer_removed
test_prune_timeout_fires_on_peer_removed
test_add_on_peer_removed_supports_multiple_listeners
test_constructor_callback_coexists_with_listeners
```

Why stacked

This PR depends on #27's `_LIFECYCLE_ALIAS_TO_CANONICAL` and `_device_id_matches` helpers; without #27, the D2D path has no canonical lifecycle name to bind against. Once #27 lands the diff against `main` is the 390 LOC here.

…D mode

The registry publishes device.{online,offline} on a shared subject
per tenant; D2D mode has no registry, so subscribing to that subject
sees nothing. Wire @on(event_name='peer_present'|'peer_lost') through
PresenceCollector callbacks when a D2D collector is present on the
device runtime, so the same decorator gives the same behavior in
both modes.

PresenceCollector grows multi-listener support (backward compatible
with the constructor-form on_new_peer pattern; new add_on_new_peer /
add_on_peer_removed methods) and emits on_peer_removed from both the
graceful-departure branch and the prune-timeout loop.

Per-device event subscriptions are unaffected; they still go through
the broker subject in both modes.

9 new tests, 437 total passing.
@kavya-chennoju kavya-chennoju merged commit 98575c9 into feat/peer-lifecycle-events May 12, 2026
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