From e7a131f9ced696729f79ba12d10e1bf1f0805fbc Mon Sep 17 00:00:00 2001 From: Leynos Date: Mon, 23 Jun 2025 20:33:24 +0100 Subject: [PATCH 1/4] Clarify push queue diagrams --- .../asynchronous-outbound-messaging-design.md | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/docs/asynchronous-outbound-messaging-design.md b/docs/asynchronous-outbound-messaging-design.md index d2b53cfe..0fcd60ff 100644 --- a/docs/asynchronous-outbound-messaging-design.md +++ b/docs/asynchronous-outbound-messaging-design.md @@ -182,41 +182,46 @@ classDiagram high_prio_tx: mpsc::Sender low_prio_tx: mpsc::Sender } - class PushHandle { + class PushHandle~F~ { +push_high_priority(frame: F): Result<(), PushError> +push_low_priority(frame: F): Result<(), PushError> +try_push(frame: F, priority: PushPriority, policy: PushPolicy): Result<(), PushError> } - class PushQueues { + class PushQueues~F~ { +high_priority_rx: mpsc::Receiver +low_priority_rx: mpsc::Receiver - +bounded(high_capacity: usize, low_capacity: usize): (PushQueues, PushHandle) + +bounded(high_capacity: usize, low_capacity: usize): (PushQueues, PushHandle~F~) +recv(): Option<(PushPriority, F)> } - PushHandleInner <.. PushHandle : contains - PushQueues o-- PushHandle : bounded() + PushHandleInner <.. PushHandle~F~ : contains + PushQueues~F~ o-- PushHandle~F~ : bounded(capacity: usize) PushHandle --> PushPriority PushHandle --> PushPolicy PushHandle --> PushError - PushQueues --> PushHandle - PushQueues --> FrameLike - PushHandle --> FrameLike + PushQueues~F~ --> PushHandle~F~ + PushQueues~F~ --> FrameLike + PushHandle~F~ --> FrameLike ``` ```mermaid flowchart TD Producer[Producer] - PushHandle[PushHandle] + Handle[PushHandle] HighQueue[High Priority Queue] LowQueue[Low Priority Queue] Policy[PushPolicy] Error[PushError or Drop] - Producer -->|push_high_priority / push_low_priority / try_push| PushHandle - PushHandle -->|High| HighQueue - PushHandle -->|Low| LowQueue - PushHandle -->|If queue full| Policy + Producer -->|push_high_priority| Handle + Handle --> HighQueue + Producer -->|push_low_priority| Handle + Handle --> LowQueue + + Producer -->|try_push| Policy + Policy -->|Queue available| Handle + Handle -->|High| HighQueue + Handle -->|Low| LowQueue Policy -->|ReturnErrorIfFull| Error Policy -->|DropIfFull| Error Policy -->|WarnAndDropIfFull| Error From f2771a4dae3844b21934bc629c14af821b45dfdc Mon Sep 17 00:00:00 2001 From: Leynos Date: Mon, 23 Jun 2025 21:12:23 +0100 Subject: [PATCH 2/4] Fix push diagram parsing --- .../asynchronous-outbound-messaging-design.md | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/asynchronous-outbound-messaging-design.md b/docs/asynchronous-outbound-messaging-design.md index 0fcd60ff..32c563f4 100644 --- a/docs/asynchronous-outbound-messaging-design.md +++ b/docs/asynchronous-outbound-messaging-design.md @@ -24,12 +24,12 @@ protocols. The implementation must satisfy the following core requirements: -| ID | Requirement | -| G1 | Any async task must be able to push frames to a live connection. | -| G2 | Ordering-safety: Pushed frames must interleave correctly with normal request/response traffic and respect any per-message sequencing rules. | -| G3 | Back-pressure: Writers must block (or fail fast) when the peer cannot drain the socket, preventing unbounded memory consumption. | -| G4 | Generic—independent of any particular protocol; usable by both servers and clients built on wireframe. | -| G5 | Preserve the simple “return a reply” path for code that does not need pushes, ensuring backward compatibility and low friction for existing users. | +| ID | Requirement | +| G1 | Any async task must be able to push frames to a live connection. | +| G2 | Ordering-safety: Pushed frames must interleave correctly with normal request/response traffic and respect any per-message sequencing rules. | +| G3 | Back-pressure: Writers must block (or fail fast) when the peer cannot drain the socket, preventing unbounded memory consumption. | +| G4 | Generic—independent of any particular protocol; usable by both servers and clients built on wireframe. | +| G5 | Preserve the simple “return a reply” path for code that does not need pushes, ensuring backward compatibility and low friction for existing users. | ## 3. Core Architecture: The Connection Actor @@ -47,7 +47,7 @@ manage two distinct, bounded `tokio::mpsc` channels for pushed frames: messages like heartbeats, session control notifications, or protocol-level pings. -2. `low_priority_push_rx: mpsc::Receiver`: For standard, non-urgent +1. `low_priority_push_rx: mpsc::Receiver`: For standard, non-urgent background messages like log forwarding or secondary status updates. The bounded nature of these channels provides an inherent and robust @@ -67,13 +67,13 @@ The polling order will be: 1. **Graceful Shutdown Signal:** The `CancellationToken` will be checked first to ensure immediate reaction to a server-wide shutdown request. -2. **High-Priority Push Channel:** Messages from `high_priority_push_rx` will be +1. **High-Priority Push Channel:** Messages from `high_priority_push_rx` will be drained next. -3. **Low-Priority Push Channel:** Messages from `low_priority_push_rx` will be +1. **Low-Priority Push Channel:** Messages from `low_priority_push_rx` will be processed after all high-priority messages. -4. **Handler Response Stream:** Frames from the active request's +1. **Handler Response Stream:** Frames from the active request's `Response::Stream` will be processed last. Rust @@ -153,8 +153,8 @@ impl PushHandle { &self, frame: F, priority: PushPriority, - policy: PushPolicy -) -> Result<(), PushError>; + policy: PushPolicy, + ) -> Result<(), PushError>; } ``` @@ -195,7 +195,7 @@ classDiagram } PushHandleInner <.. PushHandle~F~ : contains - PushQueues~F~ o-- PushHandle~F~ : bounded(capacity: usize) + PushQueues~F~ o-- PushHandle~F~ : bounded(capacity: usize) PushHandle --> PushPriority PushHandle --> PushPolicy PushHandle --> PushError @@ -347,10 +347,10 @@ features of the 1.0 release. ## 7. Measurable Objectives & Success Criteria -| Category | Objective | Success Metric | -| API Correctness | The PushHandle, SessionRegistry, and WireframeProtocol trait are implemented exactly as specified in this document. | 100% of the public API surface is present and correctly typed. | -| Functionality | Pushed frames are delivered reliably and in the correct order of priority. | A test with concurrent high-priority, low-priority, and streaming producers must show that all frames are delivered and that the final written sequence respects the strict priority order. | -| Back-pressure | A slow consumer must cause producer tasks to suspend without consuming unbounded memory. | A test with a slow consumer and a fast producer must show the producer's push().await call blocks, and the process memory usage remains stable. | -| Resilience | The SessionRegistry must not leak memory when connections are terminated. | A long-running test that creates and destroys thousands of connections must show no corresponding growth in the SessionRegistry's size or the process's overall memory footprint. | -| Performance | The overhead of the push mechanism should be minimal for connections that do not use it. | A benchmark of a simple request-response workload with the push feature enabled (but unused) should show < 2% performance degradation compared to a build without the feature. | -| Performance | The latency for a high-priority push under no contention should be negligible. | The time from push_high_priority().await returning to the frame being written to the socket buffer should be < 10µs. | +| Category | Objective | Success Metric | +| API Correctness | The PushHandle, SessionRegistry, and WireframeProtocol trait are implemented exactly as specified in this document. | 100% of the public API surface is present and correctly typed. | +| Functionality | Pushed frames are delivered reliably and in the correct order of priority. | A test with concurrent high-priority, low-priority, and streaming producers must show that all frames are delivered and that the final written sequence respects the strict priority order. | +| Back-pressure | A slow consumer must cause producer tasks to suspend without consuming unbounded memory. | A test with a slow consumer and a fast producer must show the producer's push().await call blocks, and the process memory usage remains stable. | +| Resilience | The SessionRegistry must not leak memory when connections are terminated. | A long-running test that creates and destroys thousands of connections must show no corresponding growth in the SessionRegistry's size or the process's overall memory footprint. | +| Performance | The overhead of the push mechanism should be minimal for connections that do not use it. | A benchmark of a simple request-response workload with the push feature enabled (but unused) should show < 2% performance degradation compared to a build without the feature. | +| Performance | The latency for a high-priority push under no contention should be negligible. | The time from push_high_priority().await returning to the frame being written to the socket buffer should be < 10µs. | From d4e98e926b6367589d5640a66ebbd89d30167eee Mon Sep 17 00:00:00 2001 From: Leynos Date: Mon, 23 Jun 2025 21:58:52 +0100 Subject: [PATCH 3/4] Clarify push diagrams --- .../asynchronous-outbound-messaging-design.md | 62 +++++++++++-------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/docs/asynchronous-outbound-messaging-design.md b/docs/asynchronous-outbound-messaging-design.md index 32c563f4..1a27a25e 100644 --- a/docs/asynchronous-outbound-messaging-design.md +++ b/docs/asynchronous-outbound-messaging-design.md @@ -24,12 +24,16 @@ protocols. The implementation must satisfy the following core requirements: -| ID | Requirement | -| G1 | Any async task must be able to push frames to a live connection. | -| G2 | Ordering-safety: Pushed frames must interleave correctly with normal request/response traffic and respect any per-message sequencing rules. | -| G3 | Back-pressure: Writers must block (or fail fast) when the peer cannot drain the socket, preventing unbounded memory consumption. | -| G4 | Generic—independent of any particular protocol; usable by both servers and clients built on wireframe. | -| G5 | Preserve the simple “return a reply” path for code that does not need pushes, ensuring backward compatibility and low friction for existing users. | + + +| ID | Requirement | +| G1 | Any async task must be able to push frames to a live connection. | +| G2 | Ordering-safety: Pushed frames must interleave correctly with normal request/response traffic and respect any per-message sequencing rules. | +| G3 | Back-pressure: Writers must block (or fail fast) when the peer cannot drain the socket, preventing unbounded memory consumption. | +| G4 | Generic—independent of any particular protocol; usable by both servers and clients built on wireframe. | +| G5 | Preserve the simple “return a reply” path for code that does not need pushes, ensuring backward compatibility and low friction for existing users. | + + ## 3. Core Architecture: The Connection Actor @@ -47,7 +51,7 @@ manage two distinct, bounded `tokio::mpsc` channels for pushed frames: messages like heartbeats, session control notifications, or protocol-level pings. -1. `low_priority_push_rx: mpsc::Receiver`: For standard, non-urgent +2. `low_priority_push_rx: mpsc::Receiver`: For standard, non-urgent background messages like log forwarding or secondary status updates. The bounded nature of these channels provides an inherent and robust @@ -67,13 +71,13 @@ The polling order will be: 1. **Graceful Shutdown Signal:** The `CancellationToken` will be checked first to ensure immediate reaction to a server-wide shutdown request. -1. **High-Priority Push Channel:** Messages from `high_priority_push_rx` will be +2. **High-Priority Push Channel:** Messages from `high_priority_push_rx` will be drained next. -1. **Low-Priority Push Channel:** Messages from `low_priority_push_rx` will be +3. **Low-Priority Push Channel:** Messages from `low_priority_push_rx` will be processed after all high-priority messages. -1. **Handler Response Stream:** Frames from the active request's +4. **Handler Response Stream:** Frames from the active request's `Response::Stream` will be processed last. Rust @@ -190,38 +194,38 @@ classDiagram class PushQueues~F~ { +high_priority_rx: mpsc::Receiver +low_priority_rx: mpsc::Receiver - +bounded(high_capacity: usize, low_capacity: usize): (PushQueues, PushHandle~F~) + +bounded(high_capacity: usize, low_capacity: usize): (PushQueues~F~, PushHandle~F~) +recv(): Option<(PushPriority, F)> } PushHandleInner <.. PushHandle~F~ : contains - PushQueues~F~ o-- PushHandle~F~ : bounded(capacity: usize) + PushQueues~F~ o-- PushHandle~F~ : bounded(high_capacity, low_capacity) PushHandle --> PushPriority PushHandle --> PushPolicy PushHandle --> PushError - PushQueues~F~ --> PushHandle~F~ - PushQueues~F~ --> FrameLike - PushHandle~F~ --> FrameLike ``` +The diagram uses `~F~` to represent the `` generic parameter because Mermaid +treats angle brackets as HTML. + ```mermaid flowchart TD Producer[Producer] - Handle[PushHandle] + Handle[PushHandle] HighQueue[High Priority Queue] LowQueue[Low Priority Queue] Policy[PushPolicy] Error[PushError or Drop] Producer -->|push_high_priority| Handle - Handle --> HighQueue + Handle -->|priority: High| HighQueue Producer -->|push_low_priority| Handle - Handle --> LowQueue + Handle -->|priority: Low| LowQueue Producer -->|try_push| Policy Policy -->|Queue available| Handle - Handle -->|High| HighQueue - Handle -->|Low| LowQueue + Handle -->|priority: High| HighQueue + Handle -->|priority: Low| LowQueue Policy -->|ReturnErrorIfFull| Error Policy -->|DropIfFull| Error Policy -->|WarnAndDropIfFull| Error @@ -347,10 +351,14 @@ features of the 1.0 release. ## 7. Measurable Objectives & Success Criteria -| Category | Objective | Success Metric | -| API Correctness | The PushHandle, SessionRegistry, and WireframeProtocol trait are implemented exactly as specified in this document. | 100% of the public API surface is present and correctly typed. | -| Functionality | Pushed frames are delivered reliably and in the correct order of priority. | A test with concurrent high-priority, low-priority, and streaming producers must show that all frames are delivered and that the final written sequence respects the strict priority order. | -| Back-pressure | A slow consumer must cause producer tasks to suspend without consuming unbounded memory. | A test with a slow consumer and a fast producer must show the producer's push().await call blocks, and the process memory usage remains stable. | -| Resilience | The SessionRegistry must not leak memory when connections are terminated. | A long-running test that creates and destroys thousands of connections must show no corresponding growth in the SessionRegistry's size or the process's overall memory footprint. | -| Performance | The overhead of the push mechanism should be minimal for connections that do not use it. | A benchmark of a simple request-response workload with the push feature enabled (but unused) should show < 2% performance degradation compared to a build without the feature. | -| Performance | The latency for a high-priority push under no contention should be negligible. | The time from push_high_priority().await returning to the frame being written to the socket buffer should be < 10µs. | + + +| Category | Objective | Success Metric | +| API Correctness | The PushHandle, SessionRegistry, and WireframeProtocol trait are implemented exactly as specified in this document. | 100% of the public API surface is present and correctly typed. | +| Functionality | Pushed frames are delivered reliably and in the correct order of priority. | A test with concurrent high-priority, low-priority, and streaming producers must show that all frames are delivered and that the final written sequence respects the strict priority order. | +| Back-pressure | A slow consumer must cause producer tasks to suspend without consuming unbounded memory. | A test with a slow consumer and a fast producer must show the producer's push().await call blocks, and the process memory usage remains stable. | +| Resilience | The SessionRegistry must not leak memory when connections are terminated. | A long-running test that creates and destroys thousands of connections must show no corresponding growth in the SessionRegistry's size or the process's overall memory footprint. | +| Performance | The overhead of the push mechanism should be minimal for connections that do not use it. | A benchmark of a simple request-response workload with the push feature enabled (but unused) should show < 2% performance degradation compared to a build without the feature. | +| Performance | The latency for a high-priority push under no contention should be negligible. | The time from push_high_priority().await returning to the frame being written to the socket buffer should be < 10µs. | + + From 919ce60817911c0fd360b9c03fbb64dcf780d152 Mon Sep 17 00:00:00 2001 From: Leynos Date: Tue, 24 Jun 2025 00:36:25 +0100 Subject: [PATCH 4/4] Clarify push handle flowchart --- docs/asynchronous-outbound-messaging-design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/asynchronous-outbound-messaging-design.md b/docs/asynchronous-outbound-messaging-design.md index 1a27a25e..ccdcea9d 100644 --- a/docs/asynchronous-outbound-messaging-design.md +++ b/docs/asynchronous-outbound-messaging-design.md @@ -211,7 +211,7 @@ treats angle brackets as HTML. ```mermaid flowchart TD Producer[Producer] - Handle[PushHandle] + Handle[PushHandle~F~] HighQueue[High Priority Queue] LowQueue[Low Priority Queue] Policy[PushPolicy]