Skip to main content

Config Activity API

An internal component that monitors activity (event throughput) of a group or app component. This component is automatically injected by the Kelp service; do not add it to the app config.

Event Collection

The component subscribes to all events passing through its parent group or app component via the coordinator's register-group-pulse-subscription API. Every event that flows through the parent container is counted, regardless of source or destination.

Event Handling Workflow

Subscription Lifecycle

  1. Registration: When the component initializes, it automatically registers a subscription with the coordinator for its parent group via register-group-pulse-subscription API.

  2. Activation: Subscriptions are activated when:

    • Wire connected: A wire is plugged to the component's pulse output port (detected via streamsActivated hook)
    • Editor mode: The debugger/editor activates all subscriptions by calling activate-group-pulse-subscription with groupId: null
  3. Event Collection: Once activated, the coordinator collects all events passing through the parent group:

    • Events are intercepted in the transforms-loader during wire transformation
    • Each event is emitted to the group's activity aggregator (stored in groupPulseSubscriptionsRegistered)
    • Events from all parent groups in the hierarchy are collected
  4. Aggregation: The coordinator aggregates events using EWMA:

    • Raw events are fed into createGroupActivityAggregator
    • Aggregator calculates smoothed rate and state transitions
    • Aggregated metrics are emitted back to the component
  5. Delivery: The component receives aggregated metrics and:

    • Emits them to the pulse output port
    • Reports them back to coordinator via send-group-activity-info API — BS, remove

Activation States

  • Inactive: Subscription registered but not activated. No events are collected, aggregator exists but receives no events.
  • Active (per-group): Wire connected to pulse port. Only this specific group's subscription is activated. Events are collected and aggregated.
  • Active (all groups): Editor/debugger mode. All subscriptions are activated simultaneously (groupId: null in groupPulseSubscriptionsActivated set). Used when editor needs visibility into all group activities.

Metrics Aggregation

Rate Calculation (EWMA)

The component uses Exponentially Weighted Moving Average (EWMA) for smooth rate calculation:

rate_ewma = α × instant_rate + (1 - α) × previous_rate_ewma

Where:

  • instant_rate = events in current tick × (1000 / tickMs)
  • α (ewmaAlpha) = smoothing constant (default: 0.3)

EWMA provides smooth transitions without sudden jumps when event rate changes.

Activity State Machine

The component maintains a state machine with three states:

     ┌──────┐   rate >= onRate     ┌────────┐   rate >= busyRate   ┌──────┐
│ idle │ ──────────────────▶ │ active │ ──────────────────▶ │ busy │
└──────┘ for onHoldMs └────────┘ (immediate) └──────┘
▲ │ ▲ │
│ rate <= offRate │ │ rate < busyRate │
└──────────────────────────────┘ └───────────────────────────┘
for offHoldMs (immediate)

Note: There is no direct transition between busy and idle. The busy state always transitions to active first, then active can transition to idle after hysteresis.

Hysteresis is applied to prevent flickering:

  • Transition to active requires rate ≥ onRate sustained for onHoldMs
  • Transition to idle requires rate ≤ offRate sustained for offHoldMs
  • Single events decay before hysteresis completes, avoiding spurious state changes

Configuration Parameters

ParameterDefaultDescription
EWMA Settings
tickMs250Tick interval for EWMA sampling (ms)
emitIntervalMs1000Minimum interval between emissions (ms)
ewmaAlpha0.3Smoothing constant (0-1, higher = more responsive)
rateDecimalPlaces2Number of decimal places for rate_ewma output
State Thresholds
busyRate50Rate threshold to enter busy state (events/sec)
Hysteresis
onRate1.0Rate threshold to flip idle → active
offRate0.5Rate threshold to flip active → idle
onHoldMs750How long onRate must be sustained
offHoldMs750How long off-conditions must be sustained

tickMs vs emitIntervalMs

  • tickMs: Controls EWMA sampling frequency. Smaller values = more accurate rate calculation and faster state transitions, but higher CPU usage.
  • emitIntervalMs: Controls maximum emission frequency. Use this to throttle output without affecting rate accuracy.

Example: tickMs: 100, emitIntervalMs: 1000 samples EWMA every 100ms for accurate rate tracking, but only emits updates every 1 second to avoid flooding downstream consumers.

Note: State changes always emit immediately regardless of emitIntervalMs.

Output (pulse port)

Data Structure

{
"ts": "2025-11-28T12:34:56.789Z",
"state": "active",
"rate_ewma": 3.45,
"hadEvents": true
}
FieldTypeDescription
tsstringISO 8601 timestamp of the measurement
statestringActivity state: idle, active, or busy
rate_ewmanumberSmoothed event rate (events/sec), rounded per rateDecimalPlaces
hadEventsbooleanWhether events occurred since last emission

Emission Rules

The component emits based on state and activity:

StateEmission Behavior
active/busyEmits periodic updates, throttled by emitIntervalMs
idleEmits only when new events occur, throttled by emitIntervalMs
State changeAlways emits immediately (bypasses throttling)
Rate → 0Emits once when rate becomes zero, then stops

Important Behavior Notes

  1. No continuous reporting when idle: If the group has no activity (rate = 0), the component emits once when settled and then stops. It will not continuously report "still idle".

  2. Delayed state transitions: Due to hysteresis and EWMA smoothing, state changes may be delayed:

    • Single events may not trigger active state (rate decays before hysteresis completes)
    • Transition to idle is delayed by offHoldMs after conditions are met
  3. Active state reporting: While in active or busy state, the component reports periodic updates at emitIntervalMs intervals.

  4. Idle state efficiency: While idle, emissions only occur when new events arrive, preventing unnecessary output when the system is quiet.

Example Output Sequence

// Initial state (no events yet)
{ "ts": "...", "state": "idle", "rate_ewma": 0, "hadEvents": false }

// Single event arrives
{ "ts": "...", "state": "idle", "rate_ewma": 2.4, "hadEvents": true }

// Rate settles back to zero
{ "ts": "...", "state": "idle", "rate_ewma": 0, "hadEvents": false }

// Sustained events (3-4/sec) - becomes active after hysteresis
{ "ts": "...", "state": "active", "rate_ewma": 3.2, "hadEvents": true }

// Periodic updates while active
{ "ts": "...", "state": "active", "rate_ewma": 3.5, "hadEvents": true }
{ "ts": "...", "state": "active", "rate_ewma": 3.4, "hadEvents": true }

// Events stop - becomes idle after hysteresis
{ "ts": "...", "state": "idle", "rate_ewma": 0.3, "hadEvents": false }

// Rate settles to zero
{ "ts": "...", "state": "idle", "rate_ewma": 0, "hadEvents": false }

// ... silence (no emissions until next activity)