Ready Callback for Asynchronous Task Coordination
ready-callback is a utility library designed to manage the readiness of a server or application after a series of asynchronous tasks have completed. It's particularly useful in scenarios where a server needs to wait for database connections, external service initializations, or other long-running setup processes before it can start accepting requests. The current stable version is 4.0.0, released in October 2023. This package has a moderate release cadence, with major versions aligning with Node.js LTS updates. Key differentiators include its simple callback-based API for registering tasks, robust error handling with optional 'weak' dependencies, and configurable timeouts for individual tasks or the overall ready process. It also provides status updates during task completion. Originally used heavily within the Egg.js framework ecosystem, it offers a pragmatic solution for orchestrating application startup sequences.
Common errors
-
Error: Node.js version is too low. Required Node.js >= 16.0.0
cause Attempting to use ready-callback v4.0.0 or higher on an unsupported Node.js runtime.fixUpgrade your Node.js environment to version 16.0.0 or newer. You can use tools like `nvm` to manage Node.js versions. -
TypeError: app.readyCallback is not a function
cause The `ready-callback` functionality has not been mixed into the application instance (e.g., `Koa` app).fixEnsure you call `appReady.mixin(app);` after initializing `const appReady = ready();` and before calling `app.readyCallback()`. -
ReferenceError: ready is not defined
cause The `ready` factory function was not correctly imported or required.fixFor ESM, use `import ready from 'ready-callback';`. For CJS, use `const ready = require('ready-callback');` and then `const appReady = ready();`. -
The `ready` callback never fires and the application hangs during startup.
cause One or more asynchronous tasks registered with `app.readyCallback()` never called their `done()` function, preventing the overall 'ready' state from being reached.fixReview your asynchronous task implementations to ensure that `done()` is always called, even in error conditions. Utilize timeouts (`{ timeout: ms }`) to detect hanging tasks, and consider `isWeakDep: true` for non-critical tasks.
Warnings
- breaking Version 4.0.0 dropped support for Node.js versions older than 16. Applications running on Node.js 14 or earlier will not be compatible.
- breaking Version 3.0.0 dropped support for Node.js versions older than 14. Applications on Node.js 12 or earlier will not be compatible.
- gotcha By default, if a task's callback (e.g., `done(err)`) is called with an error, the `ready` process will halt, and an 'error' event will be emitted on the main instance (e.g., `app.on('error', ...)`) but `app.ready()` will never be called.
- gotcha Tasks can be configured with a timeout. If a task does not complete (call its `done()` callback) within the specified timeout, a `ready_timeout` event will be emitted, but the ready process may continue depending on whether the task is critical or weak.
- gotcha When using `ready-callback` in TypeScript, ensure you import types correctly. While it ships with types, improper imports (e.g., trying to directly `import Ready from 'ready-callback'` for the class) can lead to type mismatches.
Install
-
npm install ready-callback -
yarn add ready-callback -
pnpm add ready-callback
Imports
- ready
import { ready } from 'ready-callback'; // 'ready' is the default export (a factory function), not a named export.import ready from 'ready-callback'; const appReady = ready();
- ReadyClass
import Ready from 'ready-callback'; // The default export is the factory function, not the class constructor itself.
import { Ready } from 'ready-callback'; const appReady = new Ready(); - readyCallback
app.readyCallback = () => {}; // Do not reassign, use the method provided after mixing in.app.readyCallback('serviceName');
Quickstart
import Koa from 'koa';
import ready from 'ready-callback';
const app = new Koa();
const appReady = ready();
// Mix the ready-callback functionality into your Koa application instance
appReady.mixin(app);
// Register an asynchronous service task
const dbConnectDone = app.readyCallback('databaseConnection');
setTimeout(() => {
console.log('Database connected!');
dbConnectDone(); // Mark the task as complete
}, 1000);
// Register another async task, e.g., loading config
const configLoadDone = app.readyCallback('configurationLoading', { timeout: 500 });
setTimeout(() => {
console.log('Configuration loaded!');
configLoadDone();
}, 300);
// The main application logic waits for all registered tasks
app.ready(() => {
console.log('All async tasks are ready. Launching server...');
app.listen(3000, () => {
console.log('Server listening on http://localhost:3000');
});
});
// Example of error handling for a task
app.on('error', (err, ctx) => {
console.error('Server error or ready-callback error:', err.message);
// Handle errors emitted by ready-callback if a task fails and is not weak
});
// Example of timeout handling
app.on('ready_timeout', (id) => {
console.warn(`Task '${id}' timed out!`);
});