You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -186,7 +186,10 @@ If no new rule is detected -> do not update the file.
186
186
- Avoid `this.` qualification; prefer predefined types (`int` over `Int32`)
187
187
- Never use `ConfigureAwait(false)`
188
188
- No magic literals - extract to constants, enums, config
189
+
- Prefer the simplest clear implementation over incidental complexity, especially on hot paths; if two fixes are correct, choose the one that is easier to reason about and keeps group operations fast
189
190
- In concurrency-sensitive paths like `OrleansHubLifetimeManager`, prefer the smallest behavior-preserving fix; avoid widening the async/concurrency shape unless tests prove it is necessary, because this code is easy to make unsafe
191
+
- Never introduce explicit `lock`/`Monitor` synchronization in Orleans-related paths; fix races via ordering, idempotent cleanup, or Orleans/concurrent primitives instead of `_syncRoot`-style locking
192
+
- For Orleans-facing changes, follow the request scheduling model explicitly: prefer grain-aligned ordering/idempotency fixes over host-side synchronization, because group operations must stay fast and consistent with Orleans execution semantics
Copy file name to clipboardExpand all lines: docs/Features/Group-Partitioning.md
+3-2Lines changed: 3 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,9 +23,10 @@ Group operations are routed through a coordinator grain that assigns group names
23
23
-[x] Add package-level batch group APIs for hub and host-service callers.
24
24
-[x] Batch coordinator and partition updates so one request does not force sequential writes per group.
25
25
-[x] Cover batch add/remove with integration tests and direct coordinator verification.
26
-
-[x] Restore disconnect-safe subscription tracking for partitioned batch adds.
26
+
-[x] Restore disconnect-safe cleanup for partitioned batch adds.
27
27
-[x] Restore the hashed cleanup fallback when batch removals see missing coordinator assignments.
28
28
-[x] Add regression tests for disconnect cleanup and degraded coordinator state.
29
+
-[x] Re-run partition cleanup when a disconnected batch join finishes late so late partition adds cannot outlive the connection.
29
30
30
31
## Main flow
31
32
@@ -47,7 +48,7 @@ flowchart TD
47
48
- Partition grains hold `group -> connection -> observer` mappings and emit fan-out to observers.
48
49
- Empty groups trigger cleanup so partitions can shed state.
49
50
- Batch membership operations collapse repeated coordinator writes into one persistence step per request and one partition write per touched partition.
50
-
-Partitioned batch adds pre-register touched partitions in the connection subscription before the coordinator write finishes so disconnect cleanup still reaches every touched partition.
51
+
-If that coordinator write finishes after the connection has already disconnected, the lifetime manager immediately issues a compensating batch remove through the coordinator so late partition adds do not recreate stale membership.
51
52
- Batch removals fall back to the hashed partition when coordinator assignment metadata is missing, which preserves cleanup in degraded-state recovery scenarios.
Copy file name to clipboardExpand all lines: docs/Features/Hub-Lifetime-Manager-Integration.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,6 +21,7 @@ The ASP.NET Core host swaps the default SignalR hub lifetime manager with `Orlea
21
21
-[x] Route package-specific batch group membership calls through the Orleans lifetime manager.
22
22
-[x] Keep batch group helper calls usable when the host is running plain `AddSignalR()`.
23
23
-[x] Add regression coverage for the batch helper path without Orleans registration.
24
+
-[x] Re-run batch partition cleanup after disconnect when a late coordinator write finishes.
24
25
25
26
## Main flow
26
27
@@ -41,6 +42,7 @@ flowchart TD
41
42
- The lifetime manager creates a per-connection `Subscription` and registers observers with connection/group/user grains.
42
43
- Package-specific batch group operations (`AddToGroupsAsync` / `RemoveFromGroupsAsync`) also route through the lifetime manager instead of looping over sequential single-group writes.
43
44
- Hub batch helpers fall back to the registered `HubLifetimeManager<THub>` when `IOrleansGroupManager<THub>` is not explicitly registered, so the API still works on plain `AddSignalR()` hosts.
45
+
- If a partitioned batch join finishes after the connection has already disconnected, the lifetime manager immediately routes a compensating batch remove through the coordinator before returning.
44
46
- Detailed batching behavior and partition persistence rules live in `docs/Features/Group-Partitioning.md`.
Copy file name to clipboardExpand all lines: docs/Features/Observer-Health-and-Circuit-Breaker.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,6 +20,7 @@ Observer delivery is protected by health tracking, circuit breaker logic, and op
20
20
-[x] Route grace-period expiration to observer cleanup and health-state removal.
21
21
-[x] Offload observer notifications from the Orleans scheduler and document why it is critical.
22
22
-[x] Add tests for circuit-breaker threshold behavior (enabled vs disabled).
23
+
-[x] Keep grace-period state transitions on the Orleans scheduler and offload only observer replay I/O.
23
24
24
25
## Main flow
25
26
@@ -41,6 +42,7 @@ flowchart TD
41
42
- Failed deliveries are recorded in a rolling failure window.
42
43
- When thresholds are exceeded, the circuit opens and delivery is skipped.
43
44
- If a grace period is configured, messages are buffered and replayed on recovery; expired grace periods remove observers.
45
+
- Grace-period recovery mutates `ObserverHealthTracker` on the grain scheduler first, then replays buffered observer callbacks off-scheduler so Orleans-owned state is never touched from a thread-pool turn.
44
46
- Without a grace period, reaching the failure threshold removes the observer immediately.
0 commit comments