npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lastshotlabs/slingshot-orchestration-bullmq

v0.2.11

Published

BullMQ-backed orchestration adapter for Slingshot tasks and workflows

Downloads

1,320

Readme

@lastshotlabs/slingshot-orchestration-bullmq

Install with Bun:

bun add @lastshotlabs/slingshot-orchestration-bullmq

This package provides a BullMQ-backed adapter for @lastshotlabs/slingshot-orchestration-engine.

Use it when you want:

  • durable task and workflow execution
  • Redis-backed queues and retries
  • progress updates through BullMQ QueueEvents
  • repeatable schedules without a separate scheduler service

What it adds

  • createBullMQOrchestrationAdapter() as the Redis-backed orchestration provider
  • queue-per-task support through TaskDefinition.queue
  • BullMQ worker processors for tasks and workflows
  • scheduling support through BullMQ repeatable jobs

Current capability profile

  • Core execution: yes
  • Scheduling: yes
  • Observability: yes
  • Progress subscriptions: yes
  • Signals: no

Provider boundary

This package depends on the portable orchestration core but not on Slingshot plugin helpers.

Typical composition:

  1. Define tasks and workflows in @lastshotlabs/slingshot-orchestration-engine
  2. Create the BullMQ adapter in this package
  3. Pass that adapter into createOrchestrationRuntime() or createOrchestrationPackage()

Minimal setup

import { createBullMQOrchestrationAdapter } from '@lastshotlabs/slingshot-orchestration-bullmq';
import { createOrchestrationRuntime } from '@lastshotlabs/slingshot-orchestration-engine';

declare const tasks: import('@lastshotlabs/slingshot-orchestration-engine').AnyResolvedTask[];
declare const workflows: import('@lastshotlabs/slingshot-orchestration-engine').AnyResolvedWorkflow[];

const adapter = createBullMQOrchestrationAdapter({
  connection: { host: '127.0.0.1', port: 6379 },
  prefix: 'orchestration',
  concurrency: 20,
});

const runtime = createOrchestrationRuntime({
  adapter,
  tasks,
  workflows,
});

When to choose BullMQ

  • Choose it when Redis is already operationally standard in the stack.
  • Choose it when you need queue-backed orchestration and repeatable schedules, but not Temporal-style signals and workflow history.
  • Do not treat it as the strongest audit system of record for active cancellation semantics; it is durable, but some stop behavior is still adapter-managed rather than natively modeled by BullMQ.

Lifecycle notes:

  • createOrchestrationPackage() starts and stops the adapter for you
  • direct createOrchestrationRuntime() usage now lazy-starts the adapter on first use
  • step-level retry and timeout overrides are carried into BullMQ child jobs so workflow behavior stays aligned with the portable runtime contract
  • idempotency keys are scoped by run type, definition name, and tenant to match the portable orchestration adapters
  • workflow hook failures emit the portable orchestration.workflow.hookError event when an event sink is configured, and otherwise fall back to console.error
  • progress subscriptions are safe to register and unregister even while the adapter is still lazily starting
  • cancelled runs stay visible through getRun() and listRuns() even when a pending BullMQ job had to be removed from the queue to stop execution
  • cancelling an active BullMQ job is still best-effort for the underlying worker code; if the adapter cannot actually stop the job, the cancel call fails instead of falsely reporting cancelled, and already-started side effects are not rolled back

Operational notes

  • Prefer explicit queue names on tasks when you need workload isolation by domain, such as quoting, binding, document generation, or downstream carrier synchronization.
  • Keep Redis persistence and retention settings aligned with how long you expect run observability data to remain useful.
  • If you need strong human-in-the-loop signaling or workflow query semantics, move to the Temporal provider instead of layering those expectations onto BullMQ.

Architecture

src/adapter.ts is the single source of truth for adapter behavior — it owns the lazy-start state machine, cancellation snapshot lifecycle, run-id caching, graceful drain, scheduling, and observability in one module. This is intentional: splitting these concerns would scatter the state transitions that must remain atomic (e.g. cancellation snapshot persistence and job removal, drain state and poller shutdown). Worker processors live in separate modules (taskWorker.ts, workflowWorker.ts) because they operate on independent lifecycles.