scheduled_tasks
The optional db-scheduler table used by distributed jobs and local event handlers.
scheduled_tasks is optional. You only need it when you use distributed jobs directly, or when you use a module that depends on distributed jobs, such as the local event handler. EventFanoutJob and EventHandlingJob are distributed jobs, so local event handling needs scheduled_tasks.
scheduled_tasks is owned by db-scheduler. Ekbatan’s JobRegistry is a small facade over db-scheduler, but it deliberately does not wrap this table in an Ekbatan model. Keep the db-scheduler schema verbatim for your dialect.
Required when: only when you use ekbatan-distributed-jobs, or any module built on it such as ekbatan-local-event-handler.
Writer: db-scheduler, through Ekbatan’s JobRegistry facade.
Row model: no Ekbatan model. db-scheduler owns this table.
DDL
1
-- db-scheduler's required schema for PostgreSQL.
2
-- This is db-scheduler's own table, so Ekbatan intentionally steps
3
-- off the always-TIMESTAMP rule here.
4
create table scheduled_tasks (
5
task_name text not null,
6
task_instance text not null,
7
task_data bytea,
8
execution_time timestamp with time zone not null,
9
picked BOOLEAN not null,
10
picked_by text,
11
last_success timestamp with time zone,
12
last_failure timestamp with time zone,
13
consecutive_failures INT,
14
last_heartbeat timestamp with time zone,
15
version BIGINT not null,
16
priority SMALLINT,
17
PRIMARY KEY (task_name, task_instance)
18
);
19
20
CREATE INDEX execution_time_idx ON scheduled_tasks (execution_time);
21
CREATE INDEX last_heartbeat_idx ON scheduled_tasks (last_heartbeat);
22
CREATE INDEX priority_execution_time_idx ON scheduled_tasks (priority desc, execution_time asc);
1
-- db-scheduler's required schema for MariaDB / MySQL.
2
-- This is db-scheduler's own table, so Ekbatan intentionally follows
3
-- db-scheduler's schema verbatim.
4
create table scheduled_tasks (
5
task_name VARCHAR(100) NOT NULL,
6
task_instance VARCHAR(100) NOT NULL,
7
task_data BLOB,
8
execution_time TIMESTAMP(6) NOT NULL,
9
picked BOOLEAN NOT NULL,
10
picked_by VARCHAR(50),
11
last_success TIMESTAMP(6) NULL,
12
last_failure TIMESTAMP(6) NULL,
13
consecutive_failures INT,
14
last_heartbeat TIMESTAMP(6) NULL,
15
version BIGINT NOT NULL,
16
priority SMALLINT,
17
PRIMARY KEY (task_name, task_instance),
18
INDEX execution_time_idx (execution_time),
19
INDEX last_heartbeat_idx (last_heartbeat),
20
INDEX priority_execution_time_idx (priority, execution_time)
21
);
1
-- db-scheduler's required schema for MySQL.
2
-- This is db-scheduler's own table, so Ekbatan intentionally follows
3
-- db-scheduler's schema verbatim.
4
create table scheduled_tasks (
5
task_name VARCHAR(100) NOT NULL,
6
task_instance VARCHAR(100) NOT NULL,
7
task_data BLOB,
8
execution_time TIMESTAMP(6) NOT NULL,
9
picked BOOLEAN NOT NULL,
10
picked_by VARCHAR(50),
11
last_success TIMESTAMP(6) NULL,
12
last_failure TIMESTAMP(6) NULL,
13
consecutive_failures INT,
14
last_heartbeat TIMESTAMP(6) NULL,
15
version BIGINT NOT NULL,
16
priority SMALLINT,
17
PRIMARY KEY (task_name, task_instance),
18
INDEX execution_time_idx (execution_time),
19
INDEX last_heartbeat_idx (last_heartbeat),
20
INDEX priority_execution_time_idx (priority, execution_time)
21
);
Columns
| Column | PostgreSQL type | MySQL/MariaDB type | Meaning |
|---|---|---|---|
task_name | text | VARCHAR(100) | Cluster-wide task name. For Ekbatan jobs this comes from DistributedJob.name(). |
task_instance | text | VARCHAR(100) | db-scheduler task instance id. Together with task_name, this is the primary key. |
task_data | bytea | BLOB | Serialized db-scheduler task payload. Ekbatan’s recurring DistributedJob facade does not expose this as application data. |
execution_time | timestamp with time zone | TIMESTAMP(6) | Next scheduled execution time. db-scheduler queries and orders by this. |
picked | BOOLEAN | BOOLEAN | Whether a scheduler instance has claimed this row for execution. |
picked_by | text | VARCHAR(50) | Identifier of the scheduler instance that claimed the row. NULL when not picked. |
last_success | timestamp with time zone | TIMESTAMP(6) | Last successful completion time, if any. |
last_failure | timestamp with time zone | TIMESTAMP(6) | Last failed completion time, if any. |
consecutive_failures | INT | INT | Number of consecutive failures recorded by db-scheduler. |
last_heartbeat | timestamp with time zone | TIMESTAMP(6) | Last heartbeat from the scheduler instance that owns the execution. Used to detect dead executions. |
version | BIGINT | BIGINT | db-scheduler’s optimistic concurrency field for claims and updates. |
priority | SMALLINT | SMALLINT | Optional scheduler priority. |
Indexes
| Index | Purpose |
|---|---|
Primary key on (task_name, task_instance) | Identifies a scheduled task instance. |
execution_time_idx on (execution_time) | Lets scheduler polling find due rows. |
last_heartbeat_idx on (last_heartbeat) | Lets db-scheduler detect stale picked executions. |
priority_execution_time_idx on priority + execution time | Lets db-scheduler poll by priority and due time. PostgreSQL examples use (priority desc, execution_time asc); MySQL/MariaDB examples use (priority, execution_time) following db-scheduler’s dialect schema. |
See also
- Framework tables — table map and optionality matrix.
- Distributed jobs — how Ekbatan uses db-scheduler.
- Local event handler — why local event handling needs distributed jobs.