Skip to content

Add EventBatcher transport#191

Open
Reversean wants to merge 6 commits into
masterfrom
feat/event-batcher
Open

Add EventBatcher transport#191
Reversean wants to merge 6 commits into
masterfrom
feat/event-batcher

Conversation

@Reversean

@Reversean Reversean commented Jun 1, 2026

Copy link
Copy Markdown
Member

Introduces EventBatcher — a Transport decorator that accumulates identical events within a configurable time window and forwards one representative message per unique signature with CatcherMessage.count set to the total number of occurrences.

Signature is computed from title, type, and per-frame coordinates (file, line, column, function) using null-byte delimiters. Lookup is O(1) via Map keyed on the signature string.

Flush is triggered by whichever condition is met first:

  • time window expires (default 5 s from first event in window)
  • buffer reaches maxBufferSize distinct signatures (default 100)
  • flush() is called explicitly (e.g. on pagehide)

BrowserCatcher wraps its transport in EventBatcher and registers a capture-phase pagehide listener to drain the buffer before the socket closes.

Protocol: CatcherMessage.count is declared via module augmentation on @hawk.so/types. Server must increment totalCount by count (defaulting to 1) and create a single Repetition record per batch.

*
* @param message - message to compute signature for
*/
function computeSignature<T extends CatcherMessageType>(message: CatcherMessage<T>): string {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets make it work like in Grouper (without backtrace)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed backtrace from key.

I think it's ok, if we still represent it as string concat, not hash as grouper does.


if (existing !== undefined) {
existing.count++;
} else {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if event is not batched, send it immediately (or with small delay to wait for duplicates)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now sending events with 5sec delay to wait duplicates.

* First occurrence is used as representative event for each batch.
* Context, user, and breadcrumbs of subsequent identical occurrences are not preserved.
*/
export class EventBatcher<T extends CatcherMessageType> implements Transport<T> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets call it "dedupe" instead of "batching" (because we will add batching later)

So lets the class EventDedupeTransport

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

import type { BacktraceFrame, CatcherMessage, CatcherMessageType } from '@hawk.so/types';
import type { Transport } from './transport';

declare module '@hawk.so/types' {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be added to the types package

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Reversean Reversean force-pushed the feat/event-batcher branch from d0c37a1 to 07cc623 Compare June 1, 2026 18:54
Comment thread packages/core/src/utils/event-dedupe-transport.ts Outdated
if (existing !== undefined) {
existing.count++;

return;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we reschedule timer here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess so. Done.

Reversean and others added 5 commits July 6, 2026 19:26
…batching

Introduces EventBatcher — a Transport decorator that accumulates identical
events within a configurable time window and forwards one representative
message per unique signature with CatcherMessage.count set to the total
number of occurrences.

Signature is computed from title, type, and per-frame coordinates
(file, line, column, function) using null-byte delimiters. Lookup is O(1)
via Map keyed on the signature string.

Flush is triggered by whichever condition is met first:
- time window expires (default 5 s from first event in window)
- buffer reaches maxBufferSize distinct signatures (default 100)
- flush() is called explicitly (e.g. on pagehide)

BrowserCatcher wraps its transport in EventBatcher and registers a
capture-phase pagehide listener to drain the buffer before the socket
closes.

Protocol: CatcherMessage.count is declared via module augmentation on
@hawk.so/types. Server must increment totalCount by count (defaulting to 1)
and create a single Repetition record per batch.
- Renamed EventBatcher to EventDedupeTransport
- removed backtrace from event key for debounce
- Decreased debounce window to 2.5s
- Reset timer on repeated message
dedupe window

- bump @hawk.so/types to 0.6.4 in core and browser, dropping the
  temporary
  CatcherMessage.count declaration merging now that it ships natively
- export EventDedupeTransport's default window as
  DEFAULT_EVENT_DEDUPE_WINDOW_MS
- switch the Catcher test suite to fake timers so tests account for the
  debounce window Catcher wires in by default, instead of assuming
  synchronous delivery to the underlying transport
- update the repeated-string-message expectation to match debounce
  merging
  duplicate messages into a single occurrence with count
@Reversean Reversean force-pushed the feat/event-batcher branch from b906ad0 to 6dd2ac1 Compare July 6, 2026 16:29
@Reversean Reversean marked this pull request as ready for review July 6, 2026 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants