EnglishGitHub
teilweisepackages/task-manager/src

Task Manager

@ralphschuler/task-manager

Plant priorisierte asynchrone Tasks innerhalb einer festen Parallelitätsgrenze.

queueconcurrencyscheduling

01 · Problem

Wofür braucht man das?

Unbegrenztes paralleles Starten überlastet CPU, Netzwerk oder Fremdsysteme; eine Queue muss Fairness, Resultate, Abbruch und Shutdown definieren.

02 · Denkmodell

Das mentale Modell

Aufgaben warten in einer Queue. Jeder freie Slot nimmt genau eine Aufgabe, gibt ihr Ergebnis zurück und startet danach den nächsten Eintrag.

Im Repository

Plant priorisierte asynchrone Tasks innerhalb einer festen Parallelitätsgrenze. Shutdown weist wartende Arbeit zurück und lässt aktive Tasks enden. CPU-Isolation und persistente Queues sind separate Aufgaben.

03 · Kontrollfluss

Was passiert in welcher Reihenfolge?

  1. Aufgabe mit resolve/reject in die Warteschlange legen.
  2. Solange Slots frei sind, den nächsten Eintrag starten.
  3. Resultat oder Fehler an den ursprünglichen Aufrufer weiterreichen.
  4. Slot im finally freigeben und sofort die nächste Aufgabe pumpen.
  5. Beim Shutdown neue Aufgaben ablehnen und Wartende definiert beenden.

04 · Bauteile

Die entscheidenden Verträge

TaskManager.addTaskLiefert ein Promise für einen priorisierten Task.
destroyLehnt wartende Arbeit ab und stoppt neue Tasks.

05 · Selbst bauen

Selbst implementieren

Ein begrenzter Promise-Scheduler zeigt das Prinzip ohne Polling und ohne echte Worker.

  1. Wartende Starts als Funktionen in einer FIFO-Queue speichern.
  2. Aktive Anzahl vor dem Start erhöhen und in finally verringern.
  3. pump nach enqueue und nach jeder Fertigstellung aufrufen.
Konzeptskizze · kann ausgelassene Helfer verwenden
class TaskQueue {
  private active = 0;
  private waiting: Array<() => void> = [];
  constructor(private limit: number) {}

  run<T>(task: () => Promise<T>) {
    return new Promise<T>((resolve, reject) => {
      this.waiting.push(() => {
        this.active++;
        task().then(resolve, reject).finally(() => { this.active--; this.pump(); });
      });
      this.pump();
    });
  }
  private pump() {
    while (this.active < this.limit && this.waiting.length) this.waiting.shift()?.();
  }
}

06 · Verifizieren

Was solltest du testen?

  • Nie laufen mehr Aufgaben als das konfigurierte Limit gleichzeitig.
  • Erfolg, Throw und Promise-Rejection geben den Slot in allen Fällen frei.
  • Shutdown entscheidet für jede wartende Aufgabe mit einem dokumentierten Fehler.

Selbst ausprobieren

Formuliere die erste Prüfaussage als fehlschlagenden Test, implementiere die kleinste Korrektur und ergänze einen Grenzfall.

Nie laufen mehr Aufgaben als das konfigurierte Limit gleichzeitig.

Ansatz vergleichen

Dein Test sollte beim gezielten Verletzen der Invariante fehlschlagen und nach der Korrektur wieder bestehen. Halte den Aufbau deterministisch und prüfe ein beobachtbares Ergebnis.

07 · Grenzen

Kompromisse und Stolperfallen

  • FIFO ist fair und kennt ohne Zusatzstruktur keine Prioritäten.
  • Promise-Concurrency begrenzt I/O, verschiebt CPU-Arbeit aber nicht in einen anderen Thread.
  • Abbruch benötigt ein Signal, das sowohl Queue als auch laufende Aufgabe verstehen.
Wichtig

Shutdown weist wartende Arbeit zurück und lässt aktive Tasks enden. CPU-Isolation und persistente Queues sind separate Aufgaben.

08 · Weiterdenken

Quellcode und verwandte Ideen

yarn tsx packages/task-manager/examples/basic.ts