Skip to content

Resource Consumption Dashboard Aggregation Race Under Streaming and REST Query Conflicts #46

Description

@elizabetheonoja-art

Resource Consumption Dashboard Aggregation Race Under Streaming and REST Query Conflicts

Problem Statement

The resource consumption aggregation in src/components/dashboard/ResourceAggregator.tsx computes running totals for water, energy, and bandwidth consumption. The aggregator receives data from two sources: a WebSocket stream (live readings, 10/s) and a REST API query (historical catch-up, every 60s). When the REST query returns historical data overlapping with live stream data, both sources attempt to update the same aggregation buckets simultaneously. The WebSocket handler adds a new reading to the current hour's bucket. The REST handler reads historical data for the past 6 hours and overwrites the current hour's bucket with the REST result (which doesn't include the latest streaming readings). The aggregator loses the last 30 seconds of streaming data every 60 seconds, producing a 0.5% undercount in the displayed total.

State Invariants & Parameters

  • WebSocket stream rate: 10 readings/second
  • REST catch-up interval: 60 seconds
  • Aggregation bucket: hourly, for past 6 hours
  • Data loss per cycle: up to 300 readings (30s × 10/s)
  • Invariant: displayed_total == Σ(live_readings) + Σ(historical_readings) without overlap

Affected Code Paths

  • src/components/dashboard/ResourceAggregator.tsx:70-115 — Dual-source update race
  • src/hooks/useResourceStream.ts:50-75 — WebSocket handler
  • src/hooks/useHistoricalQuery.ts:45-70 — REST query handler

Resolution Blueprint

  1. Implement a last-write-wins with hybrid timestamp: both sources tag their updates with a hybrid logical clock (HLC). The aggregator discards updates with stale HLCs, ensuring the streaming data (more recent) always wins over REST catch-up (older).
  2. Use differential updates instead of bucket overwrites: the REST handler computes the delta between the REST data and the current live data, only adding missing readings rather than replacing the bucket.
  3. Add a source priority system: WebSocket updates have priority 1, REST updates priority 2. Priority 1 writes are never overwritten by priority 2 writes to the same bucket.
  4. Add a concurrent dual-source test with streaming data at 10/s and a REST catch-up overlapping by 5 minutes, verifying zero data loss.

Labels

  • Complexity: Hardcore
  • Layer: Core-Engine
  • Type: Race-Condition

Metadata

Metadata

Assignees

Labels

Complexity: HardcoreIssues requiring deep systems-level engineering rigorGrantFox OSSIssue tracked in GrantFox OSSLayer: Core-EngineCore engine layerMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial CampaignCampaign: Official CampaignType: Race-ConditionConcurrency and race condition related issues

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions