A document based messaging queue for Mongo, DocumentDB, and others

Related tags

Job Queues docmq
Overview

DocMQ

Messaging Queue for any document-friendly architectures (DocumentDB, Mongo, Postgres + JSONB, etc).

Why Choose This DocMQ is a good choice if you're looking for a document based message queue built around the visibility window. If you're someonme who's frustrated that Amazon's SQS has a 15 minute maximum delay, or are trying to query Redis like it's a database, then this is probably the kind of solution you're looking for. DocMQ works with anything that holds and queries documents or document-like objects.

Why AVOID This Simple. Performance. This kind of solution will never be as fast as an in-memory Redis queue or an event bus. If fast FIFO is your goal, you should consider BullMQ, Kue, Bee, Owl, and others.

⚠️ ALPHA SOFTWARE - This is still in active development, there will be bugs. As of this writing, the basic queue/process/recurrence/delay pieces work, but there's still work to be done smoothing APIs, cleaning up typescript definitions etc.

Installation

You'll want to install DocMQ along with the mongodb client driver. This allows you to bring your own version of the mongo client in the event the MongoDB node driver changes in a material way.

Currently, DocMQ requires a Mongo Client >= 4.2 for transaction support.

# npm
npm i docmq mongodb

# yarn
yarn add docmq mongodb

# pnpm
pnpm add docmq mongodb

📚 Documentation

Creating a Queue

import { Queue, MongoDriver } from "docmq";

interface SimpleJob {
  success: boolean;
}

const queue = new Queue<SimpleJob>(
  new MongoDriver(process.env.DOC_DB_URL),
  "docmq"
);

new Queue() options

new Queue<T>(driver: Driver, name: string, options?: QueueOptions)

  • driver a Driver implementation to use such as the MongoDriver
  • name a string for the queue's name
  • options? additional options
    • retention.jobs? number of seconds to retain jobs with no further work. Default 3600 (1 hour)
    • statInterval? number of seconds between emitting a stat event with queue statistics, defaults to 5

Adding a Job to the Queue

await queue.enqueue({
  ref: "sample-id",
  /* SimpleJob */ payload: {
    success: true,
  },
});

enqueue() Options

queue.enqueue(job: JobDefinition<T> | JobDefinition<T>[])

  • job the JSON Job object, consisting of
    • ref?: string an identifier for the job, allowing future enqueue() calls to replace the job with new data. Defaults to a v4 UUID
    • payload: T the job's payload which will be saved and sent to the handler
    • runAt?: Date a date object describing when the job should run. Defaults to now()
    • runEvery?: string | null Either a cron interval or an ISO-8601 duration, or null to remove recurrence
    • retries?: number a number of tries for this job, defaults to 5
    • retryStrategy?: RetryStrategy a retry strategy, defaults to exponential

Retry Strategies

interface FixedRetryStrategy {
  type: "fixed";
  amount: number;
  jitter?: number;
}

interface ExponentialRetryStrategy {
  type: "exponential";
  min: number;
  max: number;
  factor: number;
  jitter?: number;
}

export interface LinearRetryStrategy {
  type: "linear";
  min: number;
  max: number;
  factor: number;
  jitter?: number;
}

Handling Work (Processing)

queue.process(
  async (job /* SampleJob */, api) => {
    await api.ack();
  },
  {
    /* options */
  }
);

process() Options

queue.process(handler: JobHandler<T, A, F>, config?: ProcessorConfig)

  • handler the job handler function, taking the job T and the api as arguments, returns a promise
  • config?: ProcessorConfig an optional configuration for the processor including
    • pause?: boolean should the processor wait to be started, default false
    • concurrency?: number the number of concurrent processor loops to run, default 1
    • visibility?: number specify the visibility window (how long a job is held for by default) in seconds, default 30
    • pollInterval?: number as a fallback, define how often to check for new jobs in the event that driver does not support evented notifications. Defaults to 5

api Methods and Members

  • api.ref (string) the ref value of the job
  • api.attempt (number) the attempt number for this job
  • api.visible (number) the number of seconds this job was originally reserved for
  • api.ack(result: A) acknowlegde the job, marking it complete, and scheduling future work
  • api.fail(reason: string | F) fail the job and emit the reason, scheduling a retry if required
  • api.ping(extendBy: number) on a long running job, extend the runtime by extendBy seconds

Events

The Queue object has a large number of emitted events available through queue.events. It extends EventEmitter, and the most common events are below:

  • ack when a job was acked successfully
  • fail when a job was failed
  • dead when a job has exceeded its retries and was moved to the dead letter queue
  • stats an interval ping containing information about the queue's processing load
  • start, stop when the queue starts and stops processing
  • log, warn, error logging events from the queue

🔧 Custom Driver Support

License

DocMQ source is made available under the MIT license

Comments
  • In Memory Driver

    In Memory Driver

    source

    Currently, Mongo does not work with Ubuntu 22.04, see Mongo x86 Support & Mongo ARM Support. This means that mongo-memory-server also does not work in those scenarios. For people looking to use DocMQ in an in-memory environment, this leaves no alternatives.

    Proposal

    Add support for a native JS in-memory driver as part of the DocMQ core. Here are a list of JS drivers I could find on NPM, along with the features that DocMQ needs.

    • Find/Sort At a minimum, find/sort features make it easier to update records without writing a lot of custom code inside of the driver's take, ack, etc methods.
    • changes api A method to retrieve the list of changes at the point of change. This minimizes local polling and offers better performance in the worker
    • types TS support would be ideal, but isn't a hard requirement. Having access to the types will minimize errors.

    | Library | Stars | Activity | Types | Find/Sort | Changes API | | :------------------------------------------------------ | :------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------- | :------- | :-------- | :---------- | | lowdb | GitHub Repo stars | GitHub last commit | external | lodash | no | | LokiJS | GitHub Repo stars | GitHub last commit | external | yes | yes | | ForerunnerDB | GitHub Repo stars | GitHub last commit | no | yes | yes | | PicoDB | GitHub Repo stars | GitHub last commit | no | yes | yes | | TyrDB | GitHub Repo stars | GitHub last commit | no | yes | yes | | mango-db | GitHub Repo stars | GitHub last commit | yes | yes | yes |

    As of Sept 2022, Loki seems to be the most logical choice given the stars/support and the fact it's being maintained again. LowDB does have more support, but requires lodash for find/sort features and does not offer any kind of changes API. While GitHub stars (or npm download numbers) are not a perfect indicator of project success, it does tend to identify projects with a larger audience.

    enhancement 
    opened by jakobo 6
  • Docs: improve docs and fix typos

    Docs: improve docs and fix typos

    I have noticed a typo on the docs, precisely If you're **someonme** who's frustrated... I know that's not a big deal :sweat_smile: but I think it's a good first issue :relaxed:

    Also, add contributing section in the README that redirects to the CONTRIBUTING file. And perhaps add a list of features that offer this library

    opened by TAKANOME-DEV 2
  • Research Solution for Circular Dependency Checking

    Research Solution for Circular Dependency Checking

    Problem Statement

    madge isn't great with Typescript circular dependencies. We use it right now to avoid the most egregious problems, but there's likely better solutions since the original build scripts were written.

    Proposed Solution

    This is a research task, which means no code is required (unless you want to do a PR). There's a set of questions we're hoping to answer, informing the project direction.

    1. What value are we getting from madge? How could we introduce a circular dependency in DocMQ, and can we trust madge to catch it?
    2. What alternatives to madge are out there? Are they better than what we currently have? I found two quickly googling, but this isn't an exhaustive list by any means: dpdm, eslint import rule
    3. Is it worth keeping madge, swapping to an alternative, or removing the circular dependency checks altogether?
    help wanted good first issue research 
    opened by jakobo 1
  • Postgres Driver / Supabase & Neon Support

    Postgres Driver / Supabase & Neon Support

    This is a tracking ticket for the postgres work in https://github.com/jakobo/docmq/tree/labs-postgres

    • [x] Initial driver support (https://github.com/jakobo/docmq/blob/labs-postgres/src/driver/postrgres.ts)
    • [x] Improve test suite to something that can be run against any driver (0.2.1)
    • [x] Figure out how to "init" a DB in a schema-ful environment. Currently, because Mongo is schemaless, we are rarely concerned about data migrations. Some postgres ops are idempoent, so we may be able to just run things like create table if not exists as part of the initialize() step.
    • [ ] Postgres LISTEN/NOTIFY to create a change stream. This might require creating a trigger inside of initialize() to capture inserts. For now, we can leave it on the polling system though that's less ideal.
    • [x] Explore github actions as way to do testing for postgres driver (avoid needing local driver) or look into something like pg-mem as our SQL is not very complex
    enhancement 
    opened by jakobo 1
  • Additional context on ack/fail

    Additional context on ack/fail

    Why

    Currently, job completion a job triggers an ack or fail, we can only act on the contents of the job as a generic. Some items don't serialize, making them temporary functions or classes needed only during execution and their associated events.

    Solution

    Both solutions involve creating some kind of context object that is available inside of the process step and available in the DocMQ events.

    In both cases, the emitter will need an additional generic for the context object, and we'll need to add a 4th generic to the signature Queue<T, A = unknown, F extends Error = Error, C extends Record = {}> where T is the payload type, A the ack type, F the failure type, and C the context typing.

    Context on process source when we call our processor, we can pass the context object in as a mutable object. We would need to force the type, as our starting context {} wouldn't contain any required fields. We can fix this internally by forcing the context C to DeepPartial<C> to ensure keys and nested keys are marked optional by default.

    Context on API source when we create the API, the key API methods such as ack and fail can accept an additional "context" object passed through to events. The type for the handler API would need to have an additional generic C extends Record = {}. The downside to this approach is needing to call the ack/fail explicitly with the context.

    enhancement 
    opened by jakobo 0
  • Timezone Aware runEvery Values

    Timezone Aware runEvery Values

    Currently, runEvery isn't aware of timezones. The ISO-8601 durations do not understand the politics of time, Daylight Savings, etc. The following test case highlights the error

    var luxon = require("luxon");
    const {DateTime, Duration} = luxon;
    
    const setup = [
      { zone: "America/Phoenix", diff: 24 }, // phoenix does not use DST
      { zone: "America/Los_Angeles", diff: 25 }, // LA falls back one hour
    ];
    
    const threshold = {month: 11, day: 5, hour: 14};
    const duration = Duration.fromISO("P1D");
    
    setup.forEach(t => {
      const runAt = DateTime.local()
        .setZone(t.zone)
        .set(threshold)
        .startOf("hour")
        .toISO(); // representing stored as string inside of DocMQ
      const next = DateTime.fromISO(runAt)
        .plus(duration)
        .toISO(); // add the runEvery duration
      const diff = DateTime.fromISO(next)
        .diff(DateTime.fromISO(runAt))
        .shiftTo("hours")
        .toObject().hours; // get the # of hours represented by the diff
      console.log(t.zone, `exp: ${t.diff} / act: ${diff}`, t.diff === diff);
    });
    
    "America/Phoenix", "exp: 24 / act: 25", false
    "America/Los_Angeles", "exp: 25 / act: 25", true
    

    Unfortunately, this is because there is no concept of a timezone when generating next (the process of scheduling the next occurrence based on the value in runEvery). For areas that respect Daylight Savings Time, job recurrence will be shifted by an hour at the time change boundaries which may be undesirable behavior.

    Proposed Fix

    The problem occurs during the addition of Duration to the runAt value. DocMQ isn't aware of a timezone, so it defaults to the system timezone rules when checking what P1D would evaluate to. DocMQ stored data needs to retain an optional timezone, falling back to UTC time rules for consistency.

    /** The interface used when enqueing one or many jobs */
    export interface JobDefinition<T> {
      /** A reference identifier for the job. If not specified, a v4() uuid will be used */
      ref?: string;
      /** The job's payload */
      payload: T;
      /** A date in the future when this job should run, or omit to run immediately */
      runAt?: Date;
      /** An ISO-8601 duration or a cron expression representing how frequently to run the job, or `null` to clear the value */
      runEvery?: string | null;
      /** The IANA timezone this job should occur in which scheduling future runs via `runEvery`, or `null | undefined` to use the system's time */
      timezone?: string | null | undefined;
      /** The number of allowed retries for this job before giving up and assuming the job failed. Defaults to 0 */
      retries?: number;
      /** Specify the retry strategy for the job, defaulting to a fixed retry of 5s */
      retryStrategy?: RetryStrategy;
    }
    
    • [x] Add new typings
    • [x] Store the timezone in the DocMQ database (backwards compatible schema change)
    • [x] Change the resolution of runEvery to use timezone information when available
      • Queue https://github.com/jakobo/docmq/blob/main/src/queue.ts#L190
      • BaseDriver https://github.com/jakobo/docmq/blob/b13b971db57779ef19678a49a74cc5039be919b1/src/driver/base.ts#L140
      • cron-parser has timezone support built in via the tz option key
      • luxon has support but must be told what timezone information to use via setZone()
    enhancement help wanted good first issue 
    opened by jakobo 0
  • takeAndProcess attempts to call driver with negative limit

    takeAndProcess attempts to call driver with negative limit

    Reproduction

    • Set this.workers to a value >= the allowed concurrency
    • Attempt to process a job

    Expected The takeAndProcess exits silently, as there are no available workers, retrying on worker completion or poll interval being reached

    Actual takeAndProcess passes the limit of 0 or a value <0 through to the driver which does not represent a correct limit.

    bug 
    opened by jakobo 0
  • Priority Queues

    Priority Queues

    Why

    When jobs are scheduled to run at the same time, the current take() operation on drivers does not sort for higher priority jobs.

    Solution

    • Add an additional optional "priority" field to the document
    • Add necessary indexes to allow drivers to take by visible < now, ordered by priority DESC then visible DESC
      • Loki driver change
      • Mongo driver change
      • Postgres driver change
    enhancement 
    opened by jakobo 0
  • Roadmap

    Roadmap

    This is an evergreen issue for tracking what's planned in upcoming versions of DocMQ.

    Patch 0.5.5

    • [x] Better error rejection reasons: 5b41ba4
    • [x] #13

    ...

    Major 1.0.0

    • [ ] #6
    • [ ] #14
    • [ ] Postgres migration solution
    • [ ] Major increment migration (batch script v on dequeue)
    opened by jakobo 0
  • Allow replacement of jobs in the past (when queue is inactive)

    Allow replacement of jobs in the past (when queue is inactive)

    DocMQ currently restricts replacement to jobs in the future to avoid altering a job that should already be processing. However, we can likely change the driver calls to allow the replace if:

    • deleted is null (has not completed)
    • and visible is in the past (as any acks on the job would also fail since they didn't ack or ping in time)

    This would allow you to pause the queue, do inserts, and not run into collisions for replacing a job in the past that never ran.

    enhancement 
    opened by jakobo 0
Releases(0.5.5)
  • 0.5.5(Jan 3, 2023)

    Changelog:

    • feat: Adds support for a context exposed in job processing (3acf656)
    • fix: Adds missing rejection reason to EnqueueError (5b41ba4)

    Full Changelog: https://github.com/jakobo/docmq/compare/0.5.4...0.5.5

    Source code(tar.gz)
    Source code(zip)
  • 0.5.4(Dec 7, 2022)

    Primarily a doc and internal refactor of some utilities in prep for 0.5.5 plans.

    • Documentation updates https://github.com/jakobo/docmq/commit/dc3157550652fac6411da3183dc19da16c4229f7, including notes on where DocMQ is currently used and a comparison with Bull & Agenda to help folks find the right job system for their needs
    • Switched internally from madge to dpdm #11
    • Fixes tests that were time-aware d105d34820be9bcb918a03fc80c56765c6235a2c
    • Readme cleanup

    Full Changelog: https://github.com/jakobo/docmq/compare/0.5.3...0.5.4

    Source code(tar.gz)
    Source code(zip)
  • 0.5.3(Oct 18, 2022)

    • docs: Adds 0-ver note (356477c)
    • feat: Improves transaction suport on a per-driver level (66a523a) note: this removes the external transaction API that was not in use

    Full Changelog: https://github.com/jakobo/docmq/compare/0.5.2...0.5.3

    Source code(tar.gz)
    Source code(zip)
  • 0.5.2(Oct 17, 2022)

    • fix: Fixes importing for CJS to no longer require eval bridge (c507d51)
    • chore: Removes yarn from lintstaged (f44079e)

    Full Changelog: https://github.com/jakobo/docmq/compare/0.5.1...0.5.2

    Source code(tar.gz)
    Source code(zip)
  • 0.5.1(Oct 15, 2022)

    • deps: Removes bench and dev deps to lighten package (dc845d0)
    • chore: Changes workflows to pnpm (0c33207)

    Full Changelog: https://github.com/jakobo/docmq/compare/0.5.0...0.5.1

    Source code(tar.gz)
    Source code(zip)
  • 0.5.0(Oct 14, 2022)

    💥 BREAKING CHANGES

    Event types do not allow a promise anymore, as the execution of these events were not being caught and handled. Instead, you should use an async IFFE and manage any thrown exceptions to avoid an unhandled exception error in your code.

    // @file old.ts
    Queue.on("eventName", async () => {
      //
    });
    
    // @file new.ts
    Queue.on("eventName", () => {
      // note: by declaring void, we are also claiming we've handled any thrown exceptions
      void (async () => {
        //
      })();
    });
    

    Changes

    • fix: Updates ESM-only module resolution and types for node16 - uses a custom loader pattern for ESM-only functions based on best known TS information at this time

    Full Changelog: https://github.com/jakobo/docmq/compare/0.4.6...0.5.0

    Source code(tar.gz)
    Source code(zip)
  • 0.4.6(Oct 10, 2022)

  • 0.4.5(Oct 8, 2022)

    Includes typescript @types for peer dependencies so that downstream libraries are not required to disable their lib check

    • deps: Moves peer @types to included deps (12af51d)

    Full Changelog: https://github.com/jakobo/docmq/compare/0.4.4...0.4.5

    Source code(tar.gz)
    Source code(zip)
  • 0.4.4(Oct 8, 2022)

  • 0.4.2(Oct 4, 2022)

  • 0.4.1(Sep 29, 2022)

    🔧 Fixes

    • Fix issue w/ mongo oplog test race condition (test now runs in serial since it uses a shared mongo instance)

    🧹 Misc

    • Moves to tsup, esbuild based for creating CJS/ESM bundles

    Full Changelog: https://github.com/jakobo/docmq/compare/0.4.0...0.4.1

    Source code(tar.gz)
    Source code(zip)
  • 0.4.0(Sep 28, 2022)

    💥 Breaking Changes

    • The drivers are now exported individual as docmq/driver/<name>. This is so that optional dependencies work as expected in an ESM environment. Previously, the import commands would result in attempting to include libraries that were marked as optional. Instead of import { MongoDriver} from "docmq" instead do import { MongoDriver } from "docmq/driver/mongo"

    🔧 Fixes

    • serialize-error is an ESM only module and is now imported via await import syntax for CJS compatibility

    🧹 Misc

    • Bundler was moved to unbuild which removes the headache of previously maintaining 3-4 separate tsconfig.json files. This also makes it easier to use the recommended exports:{} field for CJS/ESM compatibility.
    • Verify tests were added on build to make a CJS and ESM import respectively to ensure module entry points work as expected

    Full Changelog: https://github.com/jakobo/docmq/compare/0.3.0...0.4.0

    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(Sep 28, 2022)

    ✨ Features

    • Welcome LokiJS! A new in-memory driver is available based on LokiJS. Suitable for non-production uses, this is the recommended driver in place of the previous mongo-memory-server
    • Welcome Postgres! The new Postgres driver PGDriver is available. The PGDriver takes advantage of some of Postgres' powerful features, including generated columns to workaround null-based-indexes in PG < 14. The code was tested against tech.neon's serverless Postgres, as well as via the GitHub actions.

    🧹 Misc

    • Driver suites were cleaned up. Anything non-driver specific will use the default Memory Driver
    • GitHub Actions are set up for all push and PRs, testing against the matrix of Mongo/Postgres and node versions. We'll expand this list over time. You can also run these actions locally using act

    Issues Tagged for 0.3.0: https://github.com/jakobo/docmq/issues?q=is%3Aissue+milestone%3A0.3.0+is%3Aclosed Full Changelog: https://github.com/jakobo/docmq/compare/0.2.2...0.3.0

    Source code(tar.gz)
    Source code(zip)
  • 0.2.2(Sep 22, 2022)

    ✨ Features

    • Timezone Aware #9 DocMQ is now aware of what time it is when your job runs and can optionally keep this time associated with your job data. This is most useful for implementations where your job's execution is not dependent on the system clock but instead on a contextual time zone such as an individual user.

    🎒 Misc

    • Started adding github releases to the release-it workflow

    Changelog:

    • chore: Adds github release for changelog (1fa0ea6)
    • feat: Adds Timezone aware support for runEvery (b38ba52)
    Source code(tar.gz)
    Source code(zip)
Owner
Jakob Heuser
Jakob Heuser
Premium Queue package for handling distributed jobs and messages in NodeJS.

The fastest, most reliable, Redis-based queue for Node. Carefully written for rock solid stability and atomicity. Sponsors · Features · UIs · Install

null 13.5k Dec 31, 2022
Redis-backed task queue engine with advanced task control and eventual consistency

idoit Redis-backed task queue engine with advanced task control and eventual consistency. Task grouping, chaining, iterators for huge ranges. Postpone

Nodeca 65 Dec 15, 2022
A fast, robust and extensible distributed task/job queue for Node.js, powered by Redis.

Conveyor MQ A fast, robust and extensible distributed task/job queue for Node.js, powered by Redis. Introduction Conveyor MQ is a general purpose, dis

Conveyor MQ 45 Dec 15, 2022
Opinionated, type-safe, zero-dependency max/min priority queue for JavaScript and TypeScript projects.

qewe qewe is an opinionated, type-safe, zero-dependency max/min priority queue for JavaScript and TypeScript projects. Installation Add qewe to your p

Jamie McElwain 2 Jan 10, 2022
Kue is a priority job queue backed by redis, built for node.js.

Kue Kue is no longer maintained Please see e.g. Bull as an alternative. Thank you! Kue is a priority job queue backed by redis, built for node.js. PRO

Automattic 9.4k Dec 20, 2022
A simple, fast, robust job/task queue for Node.js, backed by Redis.

A simple, fast, robust job/task queue for Node.js, backed by Redis. Simple: ~1000 LOC, and minimal dependencies. Fast: maximizes throughput by minimiz

Bee Queue 3.1k Jan 5, 2023
Redis Simple Message Queue

Redis Simple Message Queue A lightweight message queue for Node.js that requires no dedicated queue server. Just a Redis server. tl;dr: If you run a R

Patrick Liess 1.6k Dec 27, 2022
Better Queue for NodeJS

Better Queue - Powerful flow control Super simple to use Better Queue is designed to be simple to set up but still let you do complex things. Persiste

Diamond 415 Dec 17, 2022
A simple high-performance Redis message queue for Node.js.

RedisSMQ - Yet another simple Redis message queue A simple high-performance Redis message queue for Node.js. For more details about RedisSMQ design se

null 501 Dec 30, 2022
Yet another concurrent priority task queue, yay!

YQueue Yet another concurrent priority task queue, yay! Install npm install yqueue Features Concurrency control Prioritized tasks Error handling for b

null 6 Apr 4, 2022
A client-friendly run queue

client-run-queue This package provides a RunQueue implementation for scheduling and managing async or time-consuming functions such that client-side i

Passfolio 6 Nov 22, 2022
A client-friendly run queue

client-run-queue This package provides a RunQueue implementation for scheduling and managing async or time-consuming functions such that client-side i

Passfolio 4 Jul 5, 2022
Challenge [Frontend Mentor] - In this challenge, JavaScript was used to filter jobs based on the selected categories. Technologies used: HTML5, CSS3 and React.

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

Rui Neto 11 Apr 13, 2022
A tool library for handling window && iframe && worker communication based on the JSON RPC specification

rpc-shooter A tool library for handling window && iframe && worker communication based on the JSON RPC specification 一个基于 JSON-RPC 规范用于处理 window && if

臼犀 89 Dec 20, 2022
Job queues and scheduled jobs for Node.js, Beanstalkd and/or Iron.io.

Ironium Job queues and scheduled jobs for Node.js backed by Beanstalk/IronMQ/SQS. The Why You've got a workload that runs outside the Web app's reques

Assaf Arkin 71 Dec 14, 2022
Bree is the best job scheduler for Node.js and JavaScript with cron, dates, ms, later, and human-friendly support.

The best job scheduler for Node.js and JavaScript with cron, dates, ms, later, and human-friendly support. Works in Node v10+ and browsers, uses workers to spawn sandboxed processes, and supports async/await, retries, throttling, concurrency, and graceful shutdown. Simple, fast, and lightweight. Made for @ForwardEmail and @ladjs.

Bree - The Best Node.js and JavaScript Job Scheduler 2.5k Dec 30, 2022
Type-safe and Promisified API for Web Worker and Iframe

?? You can help the author become a full-time open-source maintainer by sponsoring him on GitHub. typed-worker Install npm i typed-worker Usage Create

EGOIST 189 Dec 31, 2022
Build and deploy a roadmap voting app for your porject

Roadmap Voting App You can deploy Roadmap application yourself and get feedback from your users about your roadmap features. See the live example. In

Upstash 91 Jan 3, 2023
Making service workers easy so that your app is fast and reliable, even offline.

tulo.js Making service workers easy to use so that your app can be fast and reliable, even offline. Welcome to tulo.js, a service worker library that

OSLabs Beta 37 Nov 16, 2022