04. Streaming, Backpressure, and UI Responsiveness
Why This Topic Matters
The repo is not only orchestrating machine commands. It is also consuming ongoing data streams:
- telemetry
- preview frames
That makes the system a good place to teach a practical runtime truth:
- if producers are faster than consumers, you need a policy
The app does not pretend that every streamed item must be preserved forever. Instead, it uses bounded pipelines and makes drop or coalescing behavior visible.
Telemetry Policy
Telemetry consumption is handled by:
src/InspectionPrototype.Application/Services/TelemetryPipelineService.cs
The service documents a clear policy:
- channel capacity is
1 - lag policy uses
DropOldest - stale telemetry snapshots may be coalesced
- coalescing is recorded in counters and diagnostics
This design favors freshness over historical completeness.
That is usually the right choice for operator telemetry. A fresh value is more useful than a queue of outdated readings.
Frame Policy
Frame consumption is handled by:
src/InspectionPrototype.Application/Services/FramePipelineService.cs
The frame pipeline uses:
- channel capacity
3 DropOldest- frame-drop counters and diagnostics
This means the preview prioritizes recent frames instead of preserving a stale backlog.
The frame pipeline also runs simple fake defect detection for active runs, which makes it a good example of background consumption plus runtime mutation.
Why Visibility Matters
One of the better teaching choices in the repo is that these policies are not hidden.
The runtime exposes:
- telemetry coalescing
- frame drops
- diagnostics entries for pipeline lag
That makes backpressure visible enough for a learner to observe and reason about.
UI Responsiveness
The presentation layer still needs to remain responsive while all this background activity is happening.
MainViewModel handles that by:
- subscribing to
IAppStateStore.StateChanged - marshaling updates onto the WPF dispatcher thread
- projecting state into UI-friendly fields
This is a critical rule:
- background services may publish state from non-UI threads
- the view model is responsible for safe UI-thread projection
Avoiding Projection Churn
The view model also avoids rebuilding certain collections on every state change:
- recipe catalog
- run history
- diagnostics
- simulator profile catalog
This is a subtle performance lesson. Even if the architecture is correct, careless projection churn can still damage perceived responsiveness.
Trade-Offs
Benefits
- bounded memory behavior
- observable backpressure trade-offs
- more realistic operator-facing freshness policy
- safer UI-thread interaction
Costs
- not every telemetry or frame item is preserved
- the learner must understand that dropping or coalescing can be intentional, not automatically a bug
Related Lessons
- 05. Streaming Pipelines in .NET - Real World
- 11. Background Processing in .NET - Real World
- 12. Observability in .NET Systems - Real World
Diagram Brief
Title: Streaming, backpressure, and UI projectionPurpose: Show how telemetry and frame producers flow through bounded pipelines into canonical state and then into the WPF UIAudience: newcomer developer learning runtime data-flow trade-offsNodes: Telemetry Source, Frame Source, TelemetryPipelineService, FramePipelineService, AppStateStore, AppState, MainViewModel, WPF Dispatcher, UI PanelsEdges: sources feed pipelines; pipelines update canonical state; state changes are dispatched through MainViewModel to the UI; counters and diagnostics expose coalescing and dropsGrouping: Background producers, pipeline consumers, state owner, UI projectionCaption: Responsiveness comes from bounded pipelines plus safe UI-thread projection, not from pretending all producers and consumers run at the same speedDestination file path:docs/diagrams/source/course-04-04-streaming-backpressure-and-ui-responsiveness.drawio