Skip to content

Composition

The classes are designed to layer cleanly around promise-producing tasks.

Fluent flow

typescript
import { Flow, Semaphore } from '@haskou/flow';
import { Duration } from '@haskou/value-objects';

const value = await new Flow()
  .task((signal) => callProvider({ signal }))
  .timeout(Duration.fromSeconds(3))
  .retry({ attempts: 3 })
  .limit(new Semaphore(1))
  .run();

Use Flow when one task needs several controls and the order should stay visible at the call site.

Scheduler with a shared semaphore

typescript
import {
  Scheduler,
  SchedulerErrorPolicy,
  SchedulerOptions,
  Semaphore,
} from '@haskou/flow';
import { Duration } from '@haskou/value-objects';

const semaphore = new Semaphore(1);

const scheduler = new Scheduler(
  new SchedulerOptions(Duration.fromSeconds(5), async () => {
    await rebuildReadModel();
  }, SchedulerErrorPolicy.THROW, semaphore),
);

Rate-limited queue

typescript
import { QueueOptions, RateLimiter, RateLimiterOptions } from '@haskou/flow';
import { Duration } from '@haskou/value-objects';

const limiter = new RateLimiter(
  new RateLimiterOptions(
    Duration.fromMilliseconds(50),
    QueueOptions.withConcurrency(1),
  ),
);

await limiter.schedule(() => callProvider());

Pipeline

typescript
import {
  CircuitBreaker,
  CircuitBreakerOptions,
  FlowPipeline,
  Queue,
  RateLimiter,
  RateLimiterOptions,
} from '@haskou/flow';
import { Duration } from '@haskou/value-objects';

const pipeline = new FlowPipeline()
  .through(new Queue())
  .through(new RateLimiter(new RateLimiterOptions(Duration.fromMilliseconds(50))))
  .through(new CircuitBreaker(new CircuitBreakerOptions(3, Duration.fromSeconds(30))));

await pipeline.run(() => callProvider());

FlowPipeline is the lower-level composition object for classes that expose run(task). Prefer Flow for new code that needs timeout, retry, racing, or abortability.

Released under the MIT License.