Skip to content

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

Diagram Brief ​

  • Title: Streaming, backpressure, and UI projection
  • Purpose: Show how telemetry and frame producers flow through bounded pipelines into canonical state and then into the WPF UI
  • Audience: newcomer developer learning runtime data-flow trade-offs
  • Nodes: Telemetry Source, Frame Source, TelemetryPipelineService, FramePipelineService, AppStateStore, AppState, MainViewModel, WPF Dispatcher, UI Panels
  • Edges: sources feed pipelines; pipelines update canonical state; state changes are dispatched through MainViewModel to the UI; counters and diagnostics expose coalescing and drops
  • Grouping: Background producers, pipeline consumers, state owner, UI projection
  • Caption: Responsiveness comes from bounded pipelines plus safe UI-thread projection, not from pretending all producers and consumers run at the same speed
  • Destination file path: docs/diagrams/source/course-04-04-streaming-backpressure-and-ui-responsiveness.drawio

Docs-first project memory for AI-assisted implementation.