GitHub
Prototyppackages/stats-tracker/src

Stats Tracker

@ralphschuler/stats-tracker

Zählt Ereignisse in einem gleitenden Zeitfenster und macht kurzzeitige Aktivität messbar.

eventssliding windowmetrics

01 · Problem

Wofür braucht man das?

Ein Gesamtzähler sagt nicht, ob Aktivität gerade stattfindet; für Raten und Bursts braucht man Werte in einem definierten Zeitfenster.

02 · Denkmodell

Das mentale Modell

Jedes Ereignis erhält einen Zeitstempel. Beim Lesen werden abgelaufene Einträge entfernt und die verbleibenden Einträge gezählt.

Im Repository

Das Modul besitzt eine feste interne EventPayloadMap und speichert Zeitstempel für ein 60-Sekunden-Fenster. Bereinigung geschieht nur beim Loggen und getCount ist semantisch uneindeutig; Root-API, konfigurierbare Uhr und belastbare Tests fehlen.

03 · Kontrollfluss

Was passiert in welcher Reihenfolge?

  1. Ereignisname und aktuellen Zeitpunkt erfassen.
  2. Zeitstempel in den Bucket des Ereignisses einfügen.
  3. Beim Schreiben und Lesen alle Werte vor der Fenstergrenze entfernen.
  4. Anzahl oder Rate aus dem verbleibenden Bucket ableiten.

04 · Bauteile

Die entscheidenden Verträge

log Erfasst ein Ereignis mit dem aktuellen Timestamp.
getCount Liest den aktuellen Wert aus dem 60-Sekunden-Fenster.
EventPayloadMap (intern) Bindet bekannte Eventnamen an Payloadtypen.

05 · Build it yourself

Selbst implementieren

Mit injizierter Uhr bleibt ein gleitender Zähler klein und vollständig deterministisch testbar.

  1. Fensterlänge und now-Funktion beim Erzeugen entgegennehmen.
  2. Zeitstempel geordnet pro Ereignis speichern.
  3. Vor jeder Auswertung Einträge links bis zur Fenstergrenze entfernen.
minimal.ts · unabhängig vom Package
class WindowCounter {
  private points: number[] = [];
  constructor(private windowMs: number, private now = Date.now) {}
  add() { this.points.push(this.now()); }
  count() {
    const cutoff = this.now() - this.windowMs;
    while (this.points[0] < cutoff) this.points.shift();
    return this.points.length;
  }
}

06 · Verifizieren

Was du testen solltest

  • Einträge genau an der Fenstergrenze folgen der dokumentierten inklusiv/exklusiv-Regel.
  • Eine vorgerückte Fake-Uhr entfernt abgelaufene Einträge auch ohne neues Ereignis.
  • Getrennte Ereignisbuckets beeinflussen einander nicht.

07 · Grenzen

Kompromisse und Stolperfallen

  • Timestamp-Listen sind exakt, benötigen bei hohem Volumen jedoch viel Speicher.
  • Zeit-Buckets sparen Speicher und liefern dafür nur angenäherte Grenzen.
  • Lazy Cleanup vermeidet Timer, verlagert die Arbeit aber auf Lesezugriffe.
Wichtig

Für verteilte Systeme sind monotone Uhr, Aggregationsintervall und die Bedeutung von 'Rate' Teil des öffentlichen Vertrags.

08 · Weiterdenken

Quellcode und Nachbarn

Originalcode auf GitHub ansehen