Background Scheduler
The Joynare Nexus Background Scheduler is a highly resilient, enterprise-grade trigger framework that enables scheduling automated executions of Go-based built-in services, flows, or adapter services.
It implements a hybrid architecture combining Static Declarative Configurations (ideal for infrastructure and utility tasks) and Dynamic Database-Backed Schedules (fully manageable at runtime via REST APIs without server restarts).
📅 Architecture Overview
The scheduler leverages a coordinated execution queue utilizing a specialized, thread-safe background cron daemon (based on github.com/robfig/cron/v3 with standard 5-field cron and interval supports).
🛠️ Configuration & Schema
1. Static Configuration (config/scheduler.yaml)
Static schedules are defined inside a declarative YAML file located at config/scheduler.yaml. On server startup, these definitions are automatically loaded, checked against the registry, and scheduled.
# config/scheduler.yaml
schedules:
- name: "daily-customer-sync"
description: "Triggers ProcessCustomer flow every day at midnight"
service: "examples:ProcessCustomer"
cron: "0 0 * * *"
enabled: true
input:
sync_type: "full"
- name: "metrics-cleanup"
description: "Cleans up system transaction history logs every 5 minutes"
service: "system.utils:CleanupMetrics"
interval: "300s"
enabled: true
input: {}2. Dynamic Database Schema (scheduler_tasks table)
When MySQL database system configurations are active, Joynare Nexus automatically provisions and manages a schema to track runtime dynamic schedules:
CREATE TABLE IF NOT EXISTS scheduler_tasks (
id VARCHAR(36) PRIMARY KEY,
name VARCHAR(255) UNIQUE NOT NULL,
description TEXT,
service_key VARCHAR(255) NOT NULL,
cron_expr VARCHAR(100) NULL,
interval_seconds INT NULL,
input_json TEXT NULL,
enabled BOOLEAN DEFAULT TRUE,
last_run TIMESTAMP NULL,
next_run TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);⚡ Execution Mechanics
1. Trigger Specifications
You can configure schedules using either standard Cron Expressions or human-friendly Intervals:
- Cron Expression: Standard 5-field crons (e.g.
*/10 * * * *for every 10 minutes,0 9 * * 1-5for weekdays at 9 AM). - Interval Strings: Values inside configuration or requests are converted dynamically:
- Duration strings like
"30s","15m","3h"(supportingsfor seconds,mfor minutes,hfor hours). - Numeric expressions like
300or"300"are parsed directly as seconds.
- Duration strings like
2. Execution Isolation & Tracing
Every background run spatchcocked by the scheduler compiles its own transaction pipeline:
- Trace ID Generation: Each task sputters with a unique, traceable ID formatted as
trace-sched-<task_id>-<unix_timestamp>. This allows full trace inspection inside transaction logging. - Non-Blocking Runners: Tasks execute inside their own decoupled goroutines. If a task runs longer than its interval, the scheduler executes the subsequent tick in parallel without blocking.
- State Updates: Upon run completion,
last_runandnext_runtimestamps are calculated and dynamically updated both in the memory list and the persistent SQL database.
🌐 REST API Reference
All schedule administrative endpoints are hosted on the Design API port (default 9092) and support preflight CORS options (Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS).
1. Get Schedules
Fetches a merged list of all static and dynamic schedules, complete with run statistics.
- Method:
GET - Endpoint:
/api/admin/schedules - Response Format:
[
{
"id": "static-daily-customer-sync",
"name": "daily-customer-sync",
"description": "Triggers ProcessCustomer flow every day at midnight",
"service": "examples:ProcessCustomer",
"cron": "0 0 * * *",
"interval": 0,
"input": {
"sync_type": "full"
},
"enabled": true,
"isDynamic": false,
"lastRun": "2026-05-18T00:00:00Z",
"nextRun": "2026-05-19T00:00:00Z"
},
{
"id": "e4a2fb98-75b2-4cd8-b0a3-bf2e89643441",
"name": "dynamic-inventory-audit",
"description": "Dynamic inventory checker every hour",
"service": "inventory:AuditRecords",
"cron": "",
"interval": 3600,
"input": {},
"enabled": true,
"isDynamic": true,
"lastRun": "2026-05-18T16:00:00Z",
"nextRun": "2026-05-18T17:00:00Z"
}
]2. Save/Update Dynamic Schedule
Creates a new dynamic database task or updates an existing one if the id field matches. Saving a schedule automatically triggers a thread-safe reload of the background daemon.
- Method:
POST - Endpoint:
/api/admin/schedules - Request Body:
{
"id": "e4a2fb98-75b2-4cd8-b0a3-bf2e89643441",
"name": "dynamic-inventory-audit",
"description": "Dynamic inventory checker every hour",
"service": "inventory:AuditRecords",
"cron": "",
"interval": 3600,
"input": {},
"enabled": true
}- Response:
{
"status": "success",
"message": "Schedule saved successfully",
"id": "e4a2fb98-75b2-4cd8-b0a3-bf2e89643441"
}3. Toggle Schedule
Enables or disables a schedule. Disabling it stops scheduling ticks while keeping its database history.
- Method:
POST - Endpoint:
/api/admin/schedules/{id}/toggle - Request Body (Optional):
{
"enabled": false
}- Response:
{
"status": "success",
"message": "Schedule toggle updated successfully",
"enabled": false
}4. Trigger Manual Execute
Invokes the schedule instantly on a detached background goroutine for testing or manual operations, without altering its next scheduled execution time.
- Method:
POST - Endpoint:
/api/admin/schedules/{id}/run - Response:
{
"status": "success",
"message": "Schedule execution triggered manually in the background"
}5. Delete Dynamic Schedule
Removes a task from the database and stops background worker triggers immediately.
- Method:
DELETE - Endpoint:
/api/admin/schedules/{id} - Response:
{
"status": "success",
"message": "Schedule deleted successfully"
}