From ffc536446ca26e02eb50e84d7a01628d51130cb6 Mon Sep 17 00:00:00 2001 From: Loretta Date: Tue, 9 Jun 2026 14:51:22 +0200 Subject: [PATCH] =?UTF-8?q?Add=20PartnerDepot=20grid,=20EK=C3=81ER=20menu,?= =?UTF-8?q?=20and=20test=20refactor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added PartnerDepots navigation to Partner entity/interface - Introduced GridPartnerDepot component and detail tab in partner grid - Added EKÁER menu entry with icon and supporting styles - Moved partner/cargo tests to FruitBankPartnerTests; added PartnerDepot tests - Improved test assertions for clarity - Enabled AOT compilation by default in project file - Updated SignalR binary protocol doc with send-path analysis --- .../SIGNALR_BINARY_PROTOCOL_ISSUES.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_ISSUES.md b/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_ISSUES.md index c696f6e..c493229 100644 --- a/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_ISSUES.md +++ b/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_ISSUES.md @@ -22,7 +22,17 @@ Resolved — `TryParseChunkData` runs the blocking streaming deser off the .NET ### Fix — send (flush) side -**TBD.** The per-chunk `SyncFlush` blocking is partly inherent to streaming-with-bounded-memory under the synchronous `WriteMessage` API. To be designed; entry updated when settled. +**TBD.** Per-chunk `SyncFlush` blocks the dispatch thread under client backpressure. + +**Why it's harder than the deser side:** the blocking sits inside `IHubProtocol.WriteMessage` (synchronous, called by SignalR on a pool thread, must return when the send is done). Unlike the receive side — where *we* spawned the deser task and could move it off-pool — we don't own the calling thread here, so the "off-pool dedicated thread" trick does not apply. Within the sync `WriteMessage` contract the choice is binary: flush per chunk (bounded memory, **blocks**) or buffer the whole message + one async flush (no block, **multi-MB memory** = effectively Bytes). "Bounded memory + no block" is not reachable inside `WriteMessage`. + +**Possible solutions:** +- **A) SignalR native streaming** (`IAsyncEnumerable` / `ChannelReader`) — async backpressure, no block, bounded memory. Architecturally correct, but the consumer's dispatch is **tag-based** (`OnReceiveMessage(tag, requestId, SignalParams, data)`), not SignalR's invocation/streaming model → needs rework to fit. +- **B) Application-level batching** — send a large collection as N small Bytes-mode messages (batch index / is-last in `SignalParams`), client reassembles. Fits the tag protocol; small messages avoid the blocking flush; bounded memory + good latency. May reuse the `AcSignalRDataSource` merge pattern. *(Pragmatic favourite given the tag-based dispatch.)* +- **C) Mitigation only** — `FlushPolicy.Coalesced` + lower `FlushTimeout` reduce blocking frequency/duration but do not eliminate it under sustained backpressure. Band-aid. +- **D) Stay on Bytes** — whole-message byte[] + single async flush. No block; multi-MB memory per concurrent send. **Currently in production and stable** — so the hang is already gone; streaming would be an optimization (latency-to-first-byte / bounded memory), not a necessity. + +Direction depends on the actual goal (bounded memory → B; latency-to-first-byte → A or B; Bytes already sufficient → D). To be decided. ### Related TODO