Skip to content

Astro

since: 1.7

@runwisp/js runs scheduled tasks inside your Astro server, in astro dev and with the Node adapter. It needs a process that keeps running, so astro build fails with any other adapter, or with none.

It works with Astro 5 or later and @astrojs/node 9 or later, on Node.js or on Bun.

Terminal window
npm install @runwisp/js

Put the tasks in their own module:

src/tasks.ts
import { RunWisp } from "@runwisp/js";
import { cleanupSessions } from "./lib/sessions";
// Standalone mode has no shutdown hook: let running tasks finish, then exit.
export const runwisp = new RunWisp({ exitOnSignal: import.meta.env.PROD });
runwisp.task("cleanup-sessions", { cron: "0 * * * *" }, async () => {
const removed = await cleanupSessions();
console.log(`removed ${removed} expired sessions`);
});

Add the integration. It starts the tasks when astro dev or the built server starts:

astro.config.mjs
import { defineConfig } from "astro/config";
import node from "@astrojs/node";
import runwisp from "@runwisp/js/astro";
export default defineConfig({
adapter: node({ mode: "standalone" }),
integrations: [runwisp({ tasks: "./src/tasks.ts" })],
});

The server prints the dashboard address when the tasks start. See the JavaScript SDK for every task option.

astro dev does not reload src/tasks.ts or what it imports. Restart the dev server after you change a task.

Don’t import the tasks from src/middleware.ts: Astro loads middleware on the first request, so nothing would run until someone visits the site.

The integration keeps @runwisp/js out of the server bundle, so it finds the runwisp binary. List it under dependencies, not devDependencies, so it is installed where the server runs.

The built server starts the tasks with node dist/server/entry.mjs, or bun dist/server/entry.mjs on Bun.

In middleware mode, the tasks start when your server imports handler from dist/server/entry.mjs. Your server handles the shutdown, so leave out exitOnSignal, and close RunWisp in your shutdown code. Running tasks finish first:

server.mjs
import { RunWisp } from "@runwisp/js";
process.once("SIGTERM", async () => {
server.close();
await RunWisp.closeAll();
});

@runwisp/js has node-cron’s API, so cron.schedule() calls keep working with const cron = new RunWisp(). Give every task a name. See From node-cron.