@zarx/strapi-plugin-cron-job-manager
v0.0.1-alpha.2
Published
A cron job manager for Strapi
Maintainers
Readme
Strapi Plugin Cron Job Manager
A comprehensive cron job management plugin for Strapi v5 that provides a full-featured admin UI for managing, monitoring, and controlling your scheduled tasks.
⚠️ Development Notice: This plugin is currently in active development and not yet stable. Breaking changes may occur between versions until released. Use with caution in production environments.
Features
- 📅 Cron Job Scheduling - Define scheduled tasks using cron expressions
- 🎯 Manual Jobs - Create on-demand tasks that run only when triggered
- 🎛️ Admin UI Dashboard - View all jobs, enable/disable, trigger manually, and monitor execution
- 📊 Execution Logging - Detailed logs for every job execution with timestamps and status
- 🔄 Hot Reload Support - Job metadata updates automatically sync to the database
- 🗑️ Orphaned Job Cleanup - Delete unregistered jobs and all associated logs through the UI
- 🏷️ Rich Metadata - Add display names, descriptions, and tags to organize your jobs
- 🌍 Timezone Support - Configure timezone for each scheduled job
- 📈 Statistics - Track total jobs, active/inactive counts, and recent executions
Installation
# npm
npm install @zarx/strapi-plugin-cron-job-manager
# yarn
yarn add @zarx/strapi-plugin-cron-job-manager
# pnpm
pnpm add @zarx/strapi-plugin-cron-job-managerConfiguration
1. Enable the Plugin
In your Strapi project's config/plugins.ts (or config/plugins.js):
export default {
'cron-job-manager': {
enabled: true,
},
};2. Define Your Cron Tasks
Create a file to define your cron tasks (e.g., config/cron-tasks.ts):
import { Core } from "@strapi/strapi";
import { taskHandler } from "@zarx/strapi-plugin-cron-job-manager/strapi-server";
export default {
// Scheduled job example
dailyCleanup: {
task: taskHandler({
taskName: "dailyCleanup",
fn: async ({ strapi, executionLog }) => {
await executionLog.info("Starting daily cleanup");
// Your task logic here
const result = await strapi.db.query('api::post.post').deleteMany({
where: { publishedAt: { $null: true } }
});
await executionLog.info(`Deleted ${result} unpublished posts`);
return {
message: "Cleanup completed",
deletedCount: result,
};
},
}),
options: {
rule: "0 2 * * *", // Every day at 2 AM
tz: "America/New_York",
meta: {
displayName: "Daily Cleanup",
description: "Removes unpublished posts older than 7 days",
tags: ["maintenance", "cleanup", "daily"],
enabled: true,
},
},
},
// Manual job example
generateReport: {
task: taskHandler({
taskName: "generateReport",
fn: async ({ strapi, executionLog }) => {
await executionLog.info("Generating monthly report...");
// Your task logic here
const report = await generateMonthlyReport(strapi);
await executionLog.success("Report generated successfully");
return {
message: "Report generation completed",
reportUrl: report.url,
};
},
}),
options: {
// No 'rule' = manual job (only runs when triggered)
meta: {
displayName: "Generate Monthly Report",
description: "Manual job to generate comprehensive monthly analytics report",
tags: ["report", "manual", "analytics"],
enabled: true,
},
},
},
};3. Register Tasks in Server Config
In your config/server.ts (or config/server.js):
import cronTasks from './cron-tasks';
export default ({ env }) => ({
host: env('HOST', '0.0.0.0'),
port: env.int('PORT', 1337),
// ... other server config
cron: {
enabled: true,
tasks: cronTasks,
},
});API Reference
taskHandler(config)
Wraps your task function to provide execution logging and error handling.
Parameters:
taskName(string) - Unique identifier for the taskfn(function) - Async function containing your task logic
Function Parameters:
strapi- Strapi instance for accessing services, queries, etc.executionLog- Logging interface for the current execution
Execution Log Methods:
executionLog.info(message)- Log informational messageexecutionLog.success(message)- Log success messageexecutionLog.warning(message)- Log warning messageexecutionLog.error(message)- Log error message
Job Options
options.rule (string, optional)
Cron expression for scheduled jobs. If omitted, the job becomes a manual job that only runs when triggered.
Common cron patterns:
"0 0 * * *"- Daily at midnight"*/5 * * * *"- Every 5 minutes"0 */4 * * *"- Every 4 hours"0 9 * * 1"- Every Monday at 9 AM"0 0 1 * *"- First day of every month
Use crontab.guru to build cron expressions.
options.tz (string, optional)
Timezone for the scheduled job (e.g., "UTC", "America/New_York", "Europe/London").
options.meta (object, optional)
Metadata for the admin UI:
displayName(string) - Human-readable name shown in the UIdescription(string) - Detailed description of what the job doestags(string[]) - Array of tags for organizationenabled(boolean) - Default enabled state (only applies on first registration)
Important: The enabled state is only used when a job is first registered. After that, the enabled/disabled state is managed through the admin UI and persists across server restarts. Changing meta.enabled in code will not override the user's toggle state.
Admin UI Features
The plugin adds a "Cron Job Manager" section to your Strapi admin panel:
Dashboard View
- Statistics Cards - Overview of total jobs, active/inactive counts, recent executions
- Jobs Table - Complete list of all registered and unregistered jobs
- View job status (Active/Inactive, Scheduled/Manual, Registered/Unregistered)
- Enable/disable jobs with a toggle switch
- Trigger manual execution
- Delete unregistered jobs (with cascading log deletion)
- Click job name to view details
Job Detail View
- Job Information - Display name, description, schedule, timezone, tags
- Execution Logs - Paginated history of all executions with:
- Execution date/time
- Status (Success/Failed)
- Duration
- Result data
- Detailed logs with timestamps
Deleting Orphaned Jobs
When you remove a job from your code but it still exists in the database:
- The job appears as "Unregistered" in the jobs table
- Click the delete icon (🗑️) for that job
- Confirm deletion in the modal dialog
- The job and all associated logs are permanently deleted
This helps keep your database clean when refactoring or removing old tasks.
Complete Example
Here's a complete example showing scheduled and manual jobs:
// config/cron-tasks.ts
import { Core } from "@strapi/strapi";
import { taskHandler } from "@zarx/strapi-plugin-cron-job-manager/strapi-server";
export default {
// Scheduled: runs automatically every 5 minutes
everyFiveMinutesJob: {
task: taskHandler({
taskName: "everyFiveMinutesJob",
fn: async ({ strapi, executionLog }) => {
await executionLog.info("Scheduled 5-minute sample job started");
strapi.log.info("Scheduled 5-minute sample job executed");
return {
message: "Scheduled 5-minute sample job completed",
executedAt: new Date().toISOString(),
};
},
}),
options: {
rule: "*/5 * * * *",
tz: "UTC",
meta: {
displayName: "Every 5 Minutes Job",
description: "Sample scheduled job that runs every 5 minutes",
tags: ["sample", "scheduled", "5m"],
enabled: true,
},
},
},
// Manual: only runs when triggered from admin UI
manualHealthCheck: {
task: taskHandler({
taskName: "manualHealthCheck",
fn: async ({ executionLog }) => {
await executionLog.info("Manual health check started");
return {
message: "Manual health check completed",
checkedAt: new Date().toISOString(),
};
},
}),
options: {
// No 'rule' means manual-only
meta: {
displayName: "Manual Health Check",
description: "Example manual job. No options.rule means it only runs when triggered manually.",
tags: ["manual", "healthcheck"],
enabled: true,
},
},
},
// Scheduled but disabled by default
inactiveDeleteTestJob: {
task: taskHandler({
taskName: "inactiveDeleteTestJob",
fn: async ({ strapi, executionLog }) => {
await executionLog.info("Inactive delete-test job executed manually");
strapi.log.info("Inactive delete-test job executed manually");
return {
message: "Inactive delete-test job completed",
executedAt: new Date().toISOString(),
};
},
}),
options: {
rule: "0 0 * * *",
tz: "UTC",
meta: {
displayName: "Inactive Delete Test Job",
description: "Disabled test job used to verify inactive job handling and deletion workflows.",
tags: ["sample", "inactive", "delete-test"],
enabled: false, // Starts disabled
},
},
},
};Development
Building the Plugin
yarn buildDevelopment Mode with Hot Reload
yarn dev
# or
yarn watch:linkTesting in Playground
# Install plugin in playground
yarn playground:install
# Start playground in dev mode
yarn playground:developRequirements
- Strapi v5.37.1 or higher
- Node.js 18+ or 20+
License
MIT
Author
Johan Boström [email protected]
Issues & Contributions
- Report issues: GitHub Issues
- Repository: GitHub
