Clock and task scheduler for node.js applications, providing extensive control of time and callback scheduling in prod and test code

Overview

#zeit NPM version Build Status Coverage Status Dependency Status devDependency Status

A node.js clock and scheduler, intended to take place of the global V8 object for manipulation of time and task scheduling which would be handled with calls to set/clearTimeout and set/clearInterval. Zeit ships with a set of controllable Stub clocks which can be used for the manipulation of time and scheduling in tests.

###Why does this project exist? Writing testable code which involves the concept of time can be hard work, since you need to interact with the global "system" object in order to:

  1. Create Date object instances.
  2. Schedule callbacks to be executed at some point in the future.

In order to ensure that this behaviour is acceptably deterministic (and hence testable), we need to be able to control both of these events. The Zeit library provides objects to abstract away the global-ness of these operations, which can be used in node.js application code to provide a more managed method.

For test code you can use the bundled Stub implementations to effectively control the time in your tests, which removes the need for non-deterministic methods for asserting order and expected bevahiour, many of which rely on timeouts.

Zeit currently supports both the native JavaScript Date API and the (IMHO) superior Moment.js API.

###tl;dr Examples:

  1. Schedule a single execution of a callback for 10 seconds in the future.
new zeit.Scheduler(new zeit.DateClock())
    .execute(function () {
        return 'some happy value';
    })
    .after(10000)
    .start();
  1. Schedule a single execution of a callback at 10 seconds in the future.
new zeit.Scheduler(new zeit.DateClock())
    .execute(function () {
        return 'some happy value';
    })
    .at(new zeit.DateClock().timeIn(10000))
    .start();
  1. Schedule a Q promise to execute 5 times at 30 second intervals, starting immediately.
new zeit.Scheduler(new zeit.MomentClock())
    .execute(function () {
        return q.resolve('some happy path resolving promise');
    })
    .exactly(5)
    .atFixedIntervalOf(moment.duration(30000))
    .start();
  1. Schedule repeatedly to trigger a callback at 1 minute breaks (wait for completion) while executed less than 1000 times and no error is thrown by the callback. Starts immediately.
new zeit.Scheduler(new zeit.DateClock())
    .execute(function () {
        return 'some happy value';
    })
    .andRepeatAfter(60000)
    .whilst(function(scheduleItemDetails) {
        return scheduleItemDetails.invocationCount < 1000;
    })
    .until(function(err, result) {
        return err;
    })
    .start();

###Installation Via npm, simply run: npm install zeit

###API details Zeit requires that the same supported Date API is used consistently throughout calling code - use the wrong type and you'll get an explicit error:

  • Native Date implementation - Dates are represented as native Date objects, and durations are passed/returned as an integer number of milliseconds.
  • Moment.js implementation - Dates are represented as Moment objects and durations are passed/returned as Duration objects.

####Real clocks - zeit.DateClock / zeit.MomentClock Abstracts the creation of date objects (using now), and wraps the native set/clearTimeout & set/clearInterval methods. Also provides some utility methods below, which are required by the Scheduler implementation:

#####now() -> current date In the format relative to the implementation (see above).

#####timeIn(durationInMilliseconds) -> augmented date Returns the current date incremented by the passed duration.

#####numberOfMillisecondsAsDuration(numberOfMilliseconds) -> duration In the format relative to the implementation (see above).

#####durationUntil(datetime) -> duration In the format relative to the implementation (see above).

If you want to provide your own implementation of clock (using another Date library), you'll just need to implement these methods and then mixin an instance of TimeoutsAndIntervals.

####Stub clocks - zeit.StubDateClock / zeit.StubMomentClock Extends the Real Clock API and provides a means to control the current time by setting it directly, or implicitly/explicitly ticking by a set duration. API as above, with the following methods:

Constructor(currentDate, tickSize, implicitTickFlag)

If no values passed, the following defaults are used:

  • currentDate: Start of universal time (01-01-1970)
  • tickSize: 1 second
  • implicitTickFlag: false

#####now(newCurrentDate) -> current date Sets the current date if passed, and then returns the current date in the relative format. If implicit ticking is activated, the time will be incremented automatically by the set ticksize.

#####intervals() -> { native id -> timeout duration } Return a Hash of currently scheduled timeout durations by their timeout id.

#####timeouts() -> { native id -> timeout duration } Return a Hash of currently scheduled interval durations by their timeout id.

#####triggerAll() -> [ids of all triggered callbacks] Triggers all of the currently stored timeouts and intervals. After completion, reschedules intervals at the specified duration and discards timeouts.

#####lastKnownTime() -> current date Same as now(), but with no ticking.

#####tickSize(tickSizeInMilliseconds) -> current tick size duration If passed, sets the current ticksize.

#####tick(newTickSizeInMilliseconds) -> new current (ticked) date Increments the current date by the duration in milliseconds, or the current ticksize if not passed. Then returns the new current date.

#####implicitTick(newImplicitTickFlag) -> current implicit tick flag If passed, sets the current implicit tick flag.

####Scheduler - zeit.Scheduler Wraps the native scheduling of repeating and non-repeating callbacks or Promises/A compliant promises, but also provides the API to provide pre and post predicates to prevent execution or rescheduling or to control the number of executions. Configuration of the schedules follows the Builder pattern. The scheduler doesn't make a distinction between repeating and one-off events, rather the usage of the API determines this behaviour.

Schedulers are Event Emitters which emit the following lifecycle events for each schedule, with the latest schedule details as the message:

  • start
  • finish
  • error Note that callbacks/promises which throw exceptions (or rejected promises) emit Start & Error (no Finish event), and that throwing an exception does not cancel repeat scheduling (to stop rescheduling on an error, use the until() predicate when configuring the schedule).

#####execute(callback/promise factory function) -> Schedule Item Builder Initiates the Builder pattern for configuring the schedule item. The passed function can be either a standard callback or return a Promises/A compliant promise object. Some of the examples below and the internal Zeit implementation use the Q library.

#####activeSchedule(scheduleId) -> schedule details Returns details of the schedule, including the configuration and stats such as the invocation count and last run time.

#####cancel(scheduleId) -> schedule details Cancels the schedule and returns the latest details for that schedule, if any.

#####cancelAll() -> (scheduleId -> schedule details) Cancels all schedules and returns a Hash of the schedules cancelled.

####Schedule Item Builder (returned by execute() in Scheduler) Provides the methods to configure the schedule. Calling start() actually schedules the execution. Follows the Builder pattern, so most methods return this.

#####named(schedule name) -> schedule item builder Sets the name of the schedule.

#####after(durationInMilliseconds) -> schedule item builder Sets the initial delay before the first execution (like setTimeout).

#####at(datetime) -> schedule item builder Sets the time of the first execution (like setTimeout).

#####atFixedIntervalOf(durationInMilliseconds) -> schedule item builder Sets the repeat at a fixed rate, regardless of how long the execution takes.

#####andRepeatAfter(durationInMilliseconds) -> schedule item builder Sets the repeat at a fixed interval after execution has completed (like a tail call to setTimeout).

#####exactly(numberOfExecutions) -> schedule item builder Sets the maximum number of executions, which may be adjusted by pre and post predicates.

#####once() -> schedule item builder Syntactic-sugar for exactly(1).

#####whilst(-> boolean) -> schedule item builder Sets a pre-execution predicate, which will cancel all rescheduling once it returns false.

#####until((err, result) -> boolean) -> schedule item builder Sets a post-execution predicate, which will cancel all rescheduling once it returns true. The last execution error and result are passed to this predicate, so asserting on these values is possible.

You might also like...

Full stack CQRS, DDD, Event Sourcing framework for Node.js

Full stack CQRS, DDD, Event Sourcing framework for Node.js

reSolve is a full stack functional JavaScript framework. CQRS - independent Command and Query sides. DDD Aggregate support. Event sourcing - using eve

Dec 27, 2022

In-memory filesystem with Node's API

In-memory filesystem with Node's API

Jan 4, 2023

A simple boilerplate generator for your node express backend project! 🚀

A simple boilerplate generator for your node express backend project! 🚀

Sep 26, 2022

A nodejs module for local and remote Inter Process Communication with full support for Linux, Mac and Windows

A nodejs module for local and remote Inter Process Communication with full support for Linux, Mac and Windows

Sep 28, 2022

Actionhero is a realtime multi-transport nodejs API Server with integrated cluster capabilities and delayed tasks

Actionhero is a realtime multi-transport nodejs API Server with integrated cluster capabilities and delayed tasks

Actionhero The reusable, scalable, and quick node.js API server for stateless and stateful applications NPM | Web Site | Latest Docs | GitHub | Slack

Dec 29, 2022

:zap: RAN! React . GraphQL . Next.js Toolkit :zap: - SEO-Ready, Production-Ready, SSR, Hot-Reload, CSS-in-JS, Caching, CLI commands and more...

:zap: RAN! React . GraphQL . Next.js Toolkit :zap: - SEO-Ready, Production-Ready, SSR, Hot-Reload, CSS-in-JS, Caching, CLI commands and more...

RAN : React . GraphQL . Next.js Toolkit New version is coming... Follow up here: https://github.com/Sly777/ran/issues/677 Features Hot-Reload Ready fo

Jan 3, 2023

Fast and type-safe full stack framework, for TypeScript

Fast and type-safe full stack framework, for TypeScript

Fast and type-safe full stack framework, for TypeScript Why frourio ? Even if you write both the frontend and backend in TypeScript, you can't statica

Dec 26, 2022

A tool to develop and improve a student’s programming skills by introducing the earliest lessons of coding.

A tool to develop and improve a student’s programming skills by introducing the earliest lessons of coding.

teachcode A tool to develop and improve a student’s programming skills by introducing the earliest lessons of coding. Chat: Telegram Donate: PayPal, P

Oct 25, 2022
Comments
  • Bump lodash from 4.5.0 to 4.17.20

    Bump lodash from 4.5.0 to 4.17.20

    Bumps lodash from 4.5.0 to 4.17.20.

    Commits
    Maintainer changes

    This version was pushed to npm by bnjmnt4n, a new releaser for lodash since your current version.


    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 2
  • Bump moment from 2.11.2 to 2.27.0

    Bump moment from 2.11.2 to 2.27.0

    Bumps moment from 2.11.2 to 2.27.0.

    Changelog

    Sourced from moment's changelog.

    2.27.0 See full changelog

    • Release June 18, 2020

    Added Turkmen locale, other locale improvements, slight TypeScript fixes

    2.26.0 See full changelog

    • Release May 19, 2020

    TypeScript fixes and many locale improvements

    2.25.3

    • Release May 4, 2020

    Remove package.json module property. It looks like webpack behaves differently for modules loaded via module vs jsnext:main.

    2.25.2

    • Release May 4, 2020

    This release includes ES Module bundled moment, separate from it's source code under dist/ folder. This might alleviate issues with finding the `./locale subfolder for loading locales. This might also mean now webpack will bundle all locales automatically, unless told otherwise.

    2.25.1

    • Release May 1, 2020

    This is a quick patch release to address some of the issues raised after releasing 2.25.0.

    • 2e268635 [misc] Revert #5269 due to webpack warning
    • 226799e1 [locale] fil: Fix metadata comment
    • a83a521 [bugfix] Fix typeoff usages
    • e324334 [pkg] Add ts3.1-typings in npm package
    • 28cc23e [misc] Remove deleted generated locale en-SG

    2.25.0 See full changelog

    • Release May 1, 2020

    • #4611 022dc038 [feature] Support for strict string parsing, fixes #2469

    • #4599 4b615b9d [feature] Add support for eras in en and jp

    • #4296 757d4ff8 [feature] Accept custom relative thresholds in duration.humanize

    • 18 bigfixes

    Commits
    Maintainer changes

    This version was pushed to npm by marwahaha, a new releaser for moment since your current version.


    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
Owner
David Denton
Polyglot // Open Source // Trainer // Speaker // Kotlin GDE // Co-creator of http4k
David Denton
LoopBack makes it easy to build modern API applications that require complex integrations.

LoopBack makes it easy to build modern applications that require complex integrations. Fast, small, powerful, extensible core Generate real APIs with

StrongLoop and IBM API Connect 4.4k Jan 6, 2023
Noderlang - Erlang node in Node.js

Noderlang allows Node.js programs to easily operate in BEAM environments

devsnek 2 Mar 31, 2022
wolkenkit is an open-source CQRS and event-sourcing framework based on Node.js, and it supports JavaScript and TypeScript.

wolkenkit wolkenkit is a CQRS and event-sourcing framework based on Node.js. It empowers you to build and run scalable distributed web and cloud servi

the native web 1.1k Dec 26, 2022
The most powerful headless CMS for Node.js — built with GraphQL and React

A scalable platform and CMS to build Node.js applications. schema => ({ GraphQL, AdminUI }) Keystone Next is a preview of the next major release of Ke

KeystoneJS 7.3k Jan 4, 2023
:desktop_computer: Simple and powerful server for Node.js

server.js for Node.js Powerful server for Node.js that just works so you can focus on your awesome project: // Include it and extract some methods for

Francisco Presencia 3.5k Dec 31, 2022
Elegant and all-inclusive Node.Js web framework based on TypeScript. :rocket:.

https://foalts.org What is Foal? Foal (or FoalTS) is a Node.JS framework for creating web applications. It provides a set of ready-to-use components s

FoalTS 1.7k Jan 4, 2023
Micro type-safe wrapper for Node.js AMQP library and RabbitMQ management.

Micro type-safe wrapper for AMQP library and RabbitMQ management Description Section in progress. Getting Started Qupi can be installed by Yarn or NPM

Grzegorz Lenczuk 2 Oct 5, 2021
DDD/Clean Architecture inspired boilerplate for Node web APIs

Node API boilerplate An opinionated boilerplate for Node web APIs focused on separation of concerns and scalability. Features Multilayer folder struct

Talysson de Oliveira Cassiano 3k Dec 30, 2022
🚀 A RESTful API generator for Node.js

A RESTful API generator rest-hapi is a hapi plugin that generates RESTful API endpoints based on mongoose schemas. It provides a powerful combination

Justin Headley 1.2k Dec 31, 2022
nact ⇒ node.js + actors ⇒ your services have never been so µ

nact ⇒ node.js + actors your services have never been so µ Any and all feedback, comments and suggestions are welcome. Please open an issue if you fin

Natalie Cuthbert 1k Dec 28, 2022