docs(code-reviews): close Driver.Mqtt-006/-007 and Driver.Mqtt.Transport-002
Records the disposition and rationale for each: the primary-host gate is no longer disposed (matching MqttConnection's documented rule), a reconnect that resolves zero filters for live topics now throws like the zero-granted case it is indistinguishable from, and a password configured without a username is warned about rather than silently dropped. Both module headers drop to 0 open.
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
| Review date | 2026-08-10 |
|
||||
| Commit reviewed | `b990adae` |
|
||||
| Status | Reviewed |
|
||||
| Open findings | 2 |
|
||||
| Open findings | 0 |
|
||||
|
||||
## Checklist coverage
|
||||
|
||||
@@ -214,7 +214,7 @@ with a comment naming the extension method that needs it. Build verified.
|
||||
| Severity | Low |
|
||||
| Category | Concurrency & thread safety |
|
||||
| Location | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt/Sparkplug/SparkplugPrimaryHost.cs:278` |
|
||||
| Status | Open |
|
||||
| Status | Resolved |
|
||||
|
||||
**Description:** `DisposeAsync` calls `_gate.Dispose()`. `StopAsync` cancels the reconcile loop but
|
||||
does not await it, so a `ReconcileAsync` already in flight can be sitting in
|
||||
@@ -236,7 +236,16 @@ stated rationale — the gate holds no timer and no surviving registration), or
|
||||
the reconcile loop before dispose returns. The former is the smaller change and the one already
|
||||
argued for in this module.
|
||||
|
||||
**Resolution:** _(open)_
|
||||
**Resolution (2026-08-10):** Fixed `3f85ba98` — the first option. `DisposeAsync` no longer disposes
|
||||
`_gate`, and both the field and the dispose site now carry the rule and the reason, so the module
|
||||
states **one** answer for its lifecycle primitives rather than two. Nothing is leaked (the gate
|
||||
holds no timer and no registration) and `ClaimAsync` still re-checks `_disposed` under it, so no
|
||||
claim can be created after dispose either way. TDD: a test that disposes while a reconcile is in
|
||||
flight failed RED with `log.Captured should not contain an element satisfying (name ==
|
||||
"ObjectDisposedException") but does`. It is deterministic rather than timing-dependent — the gate is
|
||||
taken *before* the connect starts, so a `MiniBroker` in blackhole mode (TCP accepted, CONNECT never
|
||||
answered) having accepted the socket proves the claim is inside the gate when dispose runs. Suite
|
||||
green (734).
|
||||
|
||||
### Driver.Mqtt-007
|
||||
|
||||
@@ -245,7 +254,7 @@ argued for in this module.
|
||||
| Severity | Low |
|
||||
| Category | Error handling & resilience |
|
||||
| Location | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt/MqttSubscriptionManager.cs:406-424` (`OnReconnectedAsync`) |
|
||||
| Status | Open |
|
||||
| Status | Resolved |
|
||||
|
||||
**Description:** When the reconnect path finds live subscribed topics but resolves **zero** filters
|
||||
for them, it logs a warning and returns normally. The type's own contract, stated two paragraphs
|
||||
@@ -263,7 +272,19 @@ which is an argument for leaving the code alone, not for leaving the contract am
|
||||
*this* deaf-reconnect shape is exempt from the type's own rule. Do not leave the two answers side by
|
||||
side unexplained.
|
||||
|
||||
**Resolution:** _(open)_
|
||||
**Resolution (2026-08-10):** Fixed `2298485b` — it throws, and the remarks now state the single rule.
|
||||
Exempting it was considered and rejected: the reason the partial-rejection case is exempt is that
|
||||
tearing the session down would punish the tags still flowing, and here there are none — every live
|
||||
topic is in the set that resolved to nothing — so the teardown costs nothing and the retry is not
|
||||
futile, since it runs against whatever `Register` has published by then. The `subscribed.Count == 0`
|
||||
branch stays a debug no-op: a reconnect with nothing subscribed yet re-establishes nothing because
|
||||
there is nothing to establish. TDD: `Should.ThrowAsync<InvalidOperationException>` failed RED
|
||||
(`should throw System.InvalidOperationException but did not`). The test reaches the state the only
|
||||
way production can — `Register` prunes `_subscribedTopics` of the topics its new table dropped, but a
|
||||
SUBSCRIBE already in flight records its own topic *after* that prune, so a deploy landing inside the
|
||||
round-trip leaves a live topic no authored tag resolves to — driven through a `DuringSubscribe` hook
|
||||
on the existing fake transport. Paired with the control that a reconnect with no live subscriptions
|
||||
stays a no-op, which a blanket `filters.Count == 0` throw would have broken. Suite green (734).
|
||||
|
||||
### Driver.Mqtt-008
|
||||
|
||||
|
||||
Reference in New Issue
Block a user