A starter template for testing, education, development, and experimentation with the Scheduler.
π Full Documentation: Scheduler Docs
The documentation below provides a quick overview of the starter template. For comprehensive documentation, visit the official docs site.
Scheduler is a task manager that lets you write your own tasks in TypeScript/JavaScript. Based on a typed class component, users can write custom processes using any packages, libraries, and tools they wantβall while scheduling these tasks to run at specific times.
In a nutshell: Scheduler is a powerful, feature-rich CRON job manager.
- π TypeScript - Fully typed with exported types for better DX
- β‘ Bun Runtime - Faster execution with Bun and Elysia API framework
- π Lifecycle Events - Multiple lifecycle hooks for tasks (jobs)
- π Multi-Target Logging - Supports files, Loki, Gotify, and ntfy
- π¨ Integrated UI - Easy-to-use API with a tightly coupled UI
- π Built-in Networking - Includes axios for HTTP requests (more tools coming soon)
- π Authentication - JWT-based auth for both API and UI
Get up and running in 3 steps:
# 1. Pull the latest Docker images
docker-compose pull
# 2. Copy the auto-generated TypeScript types from the backend image
docker create --name=scc_b ghcr.io/moda20/scheduler_backend:latest && \
docker cp scc_b:/usr/src/app/extraTypes/types.d.ts ./types.d.ts && \
docker container rm scc_b
# the types.d.ts file copied will have all the types needed to code your job and when using the injected features like logging and notifications, an example job show how is it used
# 3. Start the stack
docker-compose up -dThe UI will be available at
http://localhost:9002(updatable in the compose file)
The starter template uses Docker Compose to launch the "Scheduler Stack"βa combination of services that handle all available features. Not all services are mandatory.
| Service | Description | Required |
|---|---|---|
scheduler_backend |
Main backend that manages jobs | β Yes |
scheduler_ui |
Web UI for managing jobs | β Yes |
mysql |
Database for jobs and authentication | β Yes |
gotify |
Notification server | β Optional |
loki |
Grafana Loki logging server | β Optional |
The scheduler uses MySQL and requires 2 databases to be created before running the backend:
CREATE DATABASE scheduler_db; -- For job definitions and stats, this is the default name and can be changed in the .env file
CREATE DATABASE scheduler_base; -- For authentication and user data, this is the default name and can be changed in the .env fileThe backend will automatically run any missing schema migrations on startup.
Configure the backend using the .env file. A complete .env.example file is provided with all default values. For detailed configuration options, see the backend repo documentation.
- Access the UI at
http://localhost:9002 - Press
Command+L(Mac) orAlt+L(Windows/Linux) to open the server configuration drawer - Enter the backend URL:
http://localhost:8080 - Optionally save the target locally for easy switching between multiple backends
- Refresh and login or register (no email verification required)
Requires 4 environment variables:
| Variable | Description |
|---|---|
GOTIFY_URL |
Host and port of your Gotify server (e.g., http://localhost:9004) |
GOTIFY_TOKEN |
User token (recommend creating a dedicated user for scheduler) |
GOTIFY_APP_TOKEN |
Application token for success notifications |
GOTIFY_ERROR_APP_TOKEN |
Application token for error/crash notifications |
Requires 3 environment variables:
| Variable | Description |
|---|---|
GRAFANA_LOKI_URL |
Host and port of your Loki server |
GRAFANA_LOKI_USERNAME |
Username for Loki authentication |
GRAFANA_LOKI_PASSWORD |
Password for Loki authentication |
Requires 3 environment variables:
| Variable | Description |
|---|---|
NTFY_URL |
Host and port of your ntfy server |
NTFY_TOKEN |
User token (recommend creating a dedicated user for scheduler) |
NTFY_TOPIC |
Target ntfy topic |
Note: Either Gotify or ntfy can be used as the default notification service, but both can also be used as regular services.
Tasks are based on the JobConsumer class. Check out exampleJob.ts for a working example.
A task consists of:
- Single file containing a class that inherits from
JobConsumer - At minimum, a
runmethod that executes your code - Ability to import any npm packages or call external services
- Export a new instance:
export default new ExampleJob();
| Name | Type | Description |
|---|---|---|
run |
function | Main method that executes your job code |
preRun |
function | Called before run - handles proxy injection and error management |
logEvent |
function | Primary logging method - sends logs to Loki if configured |
complete |
function | Call at the end of run to register success or errors |
exportResultsToFile |
function | Export results as a generic file type |
exportCacheFiles |
function | Export cache files with TTL (time-to-live) support |
injectProxies |
function | Manually inject linked proxies into axios |
axios |
object | Pre-configured axios instance with proxy support |
notifications |
object | Send notifications via Gotify or ntfy |
import { JobConsumer } from "@jobConsumer/jobConsumer";
import { JobDTO, JobLogDTO, JobOptions } from "@types/models/job";
class ExampleJob extends JobConsumer {
constructor() {
super();
}
async run(job: JobDTO, jobLog: JobLogDTO, options: JobOptions) {
// Log an event
this.logEvent("Starting example job");
// Make HTTP request using built-in axios
const response = await this.axios.get("https://api.example.com/data");
// Export results
await this.exportResultsToFile({
job_log_id: jobLog.id,
fileName: "results",
results: { data: response.data },
});
// Export cache with TTL
await this.exportCacheFiles({
job_log_id: jobLog.id,
fileName: "cache",
data: { cached: response.data },
newFile: true,
});
// Mark job as complete
return this.complete(jobLog, "");
}
}
export default new ExampleJob();You can add tasks via the API, but it's much easier through the UI:
- Click
+ New Jobon the main jobs list - Select your task file
- Enter a unique name
- Set the cron schedule
- Save!
| Login Page | Server Target Configuration | Server with Target Set |
|---|---|---|
![]() |
![]() |
![]() |
| New Job Popup | Job Popup with Fields | Jobs List | Job Running |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
| Loki Logs | Output Files & Cache | Scheduling Popup | Quick Search |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
| Database Dashboard | Proxies List |
|---|---|
![]() |
![]() |
Contributions are welcome! I (@moda20) review all PRs and test them personally. To accelerate the review process, please include:
- Clear description of changes
- Testing steps and results
- Any relevant screenshots or logs
This applies to all Scheduler services (backend & frontend) as well.
ISC License - see LICENSE for details
- π Full Documentation
- π Backend Repository
- π€ Author












