Katkat

Build a Real-Time Event Feed Dashboard

CitadelFrontend Engineer · Technical Screen

Last updated

Implement a robust React hook to manage a high-frequency, real-time event feed dashboard with pause/resume controls, out-of-order de-duplication, memory bounding, and rolling time-window statistics.

Real-Time Event Feed Manager

In trading environments, market feeds emit high-velocity bursts of messages that can arrive out of order or with duplicate sequence IDs. Your task is to implement the core state logic for a real-time event feed dashboard via a React hook named useEventFeed.

Requirements

  1. Subscription & Cleanup: Subscribe to the provided subscribe function on mount, and invoke the returned teardown function on unmount.
  2. De-duplication & Ordering: Deduplicate events by their unique id. Events must be presented in descending order of timestamp (newest first), even if they arrive out of order.
  3. Memory Bounding: Retain at most maxEvents total items in memory. Discard the oldest events when this threshold is exceeded.
  4. Pause / Resume: Expose isPaused, pause(), and resume(). When paused, newly arriving events should be buffered in the background and integrated seamlessly upon resume without dropping events (subject to maxEvents).
  5. Rolling Window Statistics: Maintain statistics for the last windowMs (default 30 seconds): total event count, event rate (events/second), and average numeric value. These stats must stay accurate even during quiet periods where no new events arrive.

Function Signature

interface FeedEvent {
  id: string;
  type: 'order' | 'trade' | 'alert';
  timestamp: number; // millisecond timestamp
  value: number;
}

interface UseEventFeedOptions {
  subscribe: (onEvent: (event: FeedEvent) => void) => () => void;
  windowMs?: number; // default: 30000
  maxEvents?: number; // default: 200
  statIntervalMs?: number; // default: 1000
}

interface UseEventFeedResult {
  events: FeedEvent[];
  eventsByType: Record;
  stats: {
    count: number;
    ratePerSecond: number;
    averageValue: number;
  };
  isPaused: boolean;
  pause: () => void;
  resume: () => void;
}

function useEventFeed(options: UseEventFeedOptions): UseEventFeedResult;

Example

// Event Stream arrives:
// t = 1000: { id: 'e1', type: 'trade', timestamp: 1000, value: 50 }
// t = 1050: { id: 'e3', type: 'trade', timestamp: 3000, value: 100 } (arrived early)
// t = 1100: { id: 'e2', type: 'order', timestamp: 2000, value: 70 }
// t = 1150: { id: 'e1', type: 'trade', timestamp: 1000, value: 50 } (duplicate)

// Current events list after t = 1150:
// [e3, e2, e1] (sorted descending by timestamp; e1 deduplicated)

Constraints & Edge Cases

  • maxEvents can range from 10 to 5000.
  • Incoming bursts can deliver up to 500 events within a single 50ms window.
  • Timestamps are positive integers (epoch ms).
  • Quiet windows: if no events arrive for 35 seconds, stats.count and stats.ratePerSecond must decay to 0 without requiring user interaction.

Hints

Hint 1

Avoid updating component state on every single incoming event during high-frequency bursts by batching updates using a ref buffer and `requestAnimationFrame` or a short interval.

Hint 2

Use a `Set` or hash map to maintain known event IDs to achieve O(1) deduplication before inserting into a sorted structure or array.

Hint 3

A background interval is necessary to periodically evict expired events from rolling calculations during periods when the feed goes quiet.

Follow-up questions

  • How would you throttle React re-renders if the WebSocket feed fires 1,000 events per second?
  • How can you avoid stale closures in your subscription callback without continuously resubscribing?
  • If `maxEvents` is increased to 50,000, how would you optimize the binary search insertion and rendering performance?