Blog
`rageDetectors` in Codebuff codebase.

`rageDetectors` in Codebuff codebase.

In this article, we review rageDetectors in Codebuff. We will look at:

  1. What is rageDetectors used for?

  2. rageDetectors definition.

I study patterns used in an open source project found on Github Trending. For this week, I reviewed Codebuff codebase and wrote this article.

What is rageDetectors used for?

In codebuff/npm-app/src/rage-detectors.ts, you will find the below comment:

/**
 * Global singleton instance of rage detectors.
 * This allows rage detection to be used anywhere in the application.
 */
export const rageDetectors: RageDetectors = createRageDetectors()

It tells us that this detection mechanism can be used across the application, but what are these rage detectors? Codebuff classifies the following as rageDetectors:

  1. keyMashingDetector

  2. repeatInputDetector

  3. exitAfterErrorDetector

  4. webSocketHangDetector

  5. startupTimeDetector

  6. exitTimeDetector

You will find these functions are returned by createRageDetectors function.

rageDetectors definition.

The following is definition of rageDetectors:

export function createRageDetectors(): RageDetectors {
  return {
    keyMashingDetector: createCountDetector({
      reason: 'key_mashing',
      mode: 'COUNT',
      threshold: 5,
      timeWindow: 1000,
      historyLimit: 20,
      debounceMs: 5_000,
      filter: ({ str, key }) => {
      },
    }),

    repeatInputDetector: createCountDetector({
      reason: 'repeat_input',
      mode: 'COUNT',
      threshold: 3,
      timeWindow: 30_000,
      historyLimit: 10,
      debounceMs: 10_000,
    }),

    exitAfterErrorDetector: createTimeBetweenDetector({
      reason: 'exit_after_error',
      mode: 'TIME_BETWEEN',
      threshold: 10_000,
      operator: 'lt',
    }),

    webSocketHangDetector: createTimeoutDetector<WebSocketHangDetectorContext>({
      reason: 'websocket_persistent_failure',
      timeoutMs: 60_000,
      shouldFire: async (context) => {
        if (!context || !context.getWebsocketState) {
          return false
        }

        // Add a 2-second grace period for reconnection
        await sleep(2000)

        // Only fire if the websocket is still not connected.
        // This prevents firing if the connection is restored right before the timeout.
        return context.getWebsocketState() !== WebSocket.OPEN
      },
    }),

    startupTimeDetector: createTimeBetweenDetector({
      reason: 'slow_startup',
      mode: 'TIME_BETWEEN',
      threshold: 5_000,
      operator: 'gte',
      debounceMs: 30_000,
    }),

    exitTimeDetector: createTimeBetweenDetector({
      reason: 'slow_exit',
      mode: 'TIME_BETWEEN',
      threshold: 10_000,
      operator: 'gte',
      debounceMs: 30_000,
    }),
  }
}

createCountDetector, createTimeBetweenDetector, createTimeoutDetector are imported as shown below:

import {
  createCountDetector,
  createTimeBetweenDetector,
  createTimeoutDetector,
} from './utils/rage-detector'

You will find the following declaration in npm-app/src/utils/rage-detector.ts#L49.

// Factory function for COUNT-based detectors
export function createCountDetector(options: CountDetectorOptions) {
  let history: EventRecord[] = []
  let debounceTimer: NodeJS.Timeout | null = null

  const recordEvent = (value?: any) => {
  }

  const checkForRage = () => {
  }

  const fireEvent = (events: EventRecord[]) => {
  }

  return { recordEvent }
}

// Factory function for TIME_BETWEEN-based detectors
export function createTimeBetweenDetector(options: TimeBetweenDetectorOptions) {
  let startEvent: EventRecord | null = null
  let coolDownTimer: NodeJS.Timeout | null = null

  const start = () => {
    startEvent = { timestamp: Date.now(), value: null }
  }

  const end = () => {
  }

  const fireEvent = (duration: number) => {
  }

  return { start, end }
}

// Factory function for TIMEOUT-based detectors
export function createTimeoutDetector<
  TContext extends Record<string, any> = Record<string, any>,
>(options: {
  reason: string
  timeoutMs: number
  onHang?: () => void
  context?: TContext
  shouldFire?: (context?: TContext) => boolean | Promise<boolean>
}) {
  let timeoutHandle: NodeJS.Timeout | null = null

  const start = (context?: TContext) => {
  }

  const stop = () => {
  }

  return { start, stop }
}

About me:

Hey, my name is Ramu Narasinga. I study codebase architecture in large open-source projects.

Email: ramu.narasinga@gmail.com

Want to learn from open-source? Solve challenges inspired by open-source projects.

References:

  1. https://github.com/CodebuffAI/codebuff/blob/main/npm-app/src/index.ts#L24

  2. https://github.com/CodebuffAI/codebuff/blob/main/npm-app/src/rage-detectors.ts

  3. https://github.com/CodebuffAI/codebuff/blob/main/npm-app/src/utils/rage-detector.ts#L49