tasks — Task registry backed by SQLite (via sigma/sqlite JDBC wrapper).
Overview
A persistent task registry to schedule and track execution of automation scripts across devices.
- Main table: tasks (one row per task)
- Child table: task_paths (one task → many paths)
- Devices master: task_devices (deduplicated by
(device_name, device_sn)) - Relation table: task_path_devices (many-to-many between paths and devices)
The public API returns camelCase fields and keeps backward-friendly names where required。
Key Features
- Connection & Pragmas: WAL, NORMAL sync, busy timeout.
- Create:
tasksCreate()supports both the simple signature and a full object withoptions. - Update:
tasksUpdate()handles camelCase → snake_case mapping for main task fields and
recomputesplan_timewhenrepeat/timeis changed. - Delete:
tasksDelete()&tasksDeleteMany()with cascade cleanup via FKs. - Query:
tasksList()/tasksGet()aggregate paths and devices intooptionsfor output. - Search/Count: LIKE-based search across key fields; status grouping.
- Controls:
tasksPause()/tasksResume()/tasksStop()delegate to the underlying executor.
Status Values (negative convention kept)
0 : FILE_NOT_FOUND — Script path does not exist (pre-run validation failure)
-1 : RUNNING
-2 : STOPPED_NORMAL
-3 : STOPPED_ERROR
-4 : PAUSED
-5 : USER_TERMINATED
-6 : SCHEDULED (default upon creation)
Storage — Tables
tasks (main)
id INTEGER PK AUTOINCREMENTauto_connect INTEGER NOT NULL DEFAULT 0auto_select INTEGER NOT NULL DEFAULT 0start_time INTEGER NOT NULL// ms epochend_time INTEGER// ms epocherror_message TEXT NOT NULL DEFAULT ''exec_count INTEGER NOT NULL DEFAULT 1exec_device TEXT NOT NULL DEFAULT '-'expiration INTEGER NOT NULL DEFAULT 0iter_count INTEGER NOT NULL DEFAULT 1plan_time INTEGER// ms epoch; computed fromtime/repeatre_exec INTEGER NOT NULL DEFAULT 0status INTEGER NOT NULL DEFAULT -6task_id INTEGER NOT NULL UNIQUE// business-visible idtask_name TEXT NOT NULL UNIQUEweek_json TEXT// optional serialized repeat weekdays ["0".."6"]created_at INTEGER NOT NULL// ms epochupdated_at INTEGER NOT NULL// ms epochtimezone TEXT NOT NULL// e.g. "Asia/Shanghai"sigma_test_status TEXT DEFAULT NULL// e.g. "{T:320,P:280,F:30,E:10}"
Indexes: by status, plan_time, updated_at, and LIKE on task_name.
task_paths
id INTEGER PK AUTOINCREMENTtask_row_id INTEGER NOT NULL// FK → tasks.id (row id)path TEXT NOT NULLcreated_at INTEGER NOT NULL// ms epochupdated_at INTEGER NOT NULL// ms epoch
task_devices (master)
id INTEGER PK AUTOINCREMENTdevice_name TEXT NOT NULLdevice_sn TEXT NOT NULLcreated_at INTEGER NOT NULL// ms epochupdated_at INTEGER NOT NULL// ms epochUNIQUE(device_name, device_sn)
task_path_devices (relation)
(task_path_id INTEGER, task_device_id INTEGER)as composite PKcreated_at INTEGER NOT NULL// ms epoch- FKs cascade on delete of path/device
Returned Shapes
Both tasksList() and tasksGet() return objects in this format (example array with one item):
[{
"autoConnect": false,
"autoSelect": false,
"startTime": 1757922442739,
"endTime": 1757922442782,
"errorMessage": "",
"execCount": 1,
"execDevice": "-",
"expiration": 0,
"iterCount": 1,
"reExec": false,
"options": [
{ "device_names": [], "device_sn": [], "path": "C:/.../1.js" }
],
"status": -2,
"taskID": 1759213730566,
"taskName": "1111(3)",
"createdAt": 1757922442739,
"updatedAt": 1757922442739,
"timezone": "Asia/Shanghai",
"sigma_test_status": "{T:320,P:280,F:30,E:10}"
}]
Notes:
createdAt/updatedAtare long (ms epoch), not ISO strings.
Simple Overload Enhancements
- Adds support for
tasksCreate(name, scriptFile, options)signature. - The
optionsobject may include:iteration: number— number of executions.time: string— "YYYY-MM-DD HH:mm[:ss]" (one-shot) or "HH:mm[:ss]" (repeat).repeat: number[]— weekdays [0..6]; e.g., [1,3,5] for Mon/Wed/Fri.deviceName: string|string[]— single device (also accepts one-element array).deviceNames: string[]— multiple devices.deviceSN: string|string[]anddeviceSNs: string[]— optional serial numbers.
- When the counts of
deviceName(s)anddeviceSN(s)differ, the shorter array is automatically padded with empty strings"". - All inserts (
tasks,task_paths, andtask_path_devices) occur within the same transaction. - Backward compatible with
(name, scriptFile, iteration?, time?, repeat?).
Example Usage
var tasks = require("sigma/tasks");
// Simple creation (single path, no devices):
tasks.tasksCreate("nightly", "C:/Scripts/a.js", 1, "2025-12-01 08:00");
// Listing (aggregates options from normalized tables):
var list = tasks.tasksList({ status: tasks.STATUS.SCHEDULED, limit: 20 });
print(JSON.stringify(list, null, 2));
// Simplified object overload
tasksCreate("task001", "F:/test/test.js", { iteration: 2 });
tasksCreate("task002", "F:/test/test.js", { iteration: 1, time: "2020-06-30 14:30" });
tasksCreate("task003", "F:/test/test.js", { iteration: 1, time: "14:30", repeat: [3,5] });
// Single device
tasksCreate("task004", "F:/File/text.js", { iteration: 1, time: "14:30", repeat: [3,5], deviceName: ["PIONEER K88L"] });
// Multiple devices
tasksCreate("task005", "E:/File/test.js", { iteration: 1, time: "2020-07-30 15:30", deviceNames: ["PIONEER K88L","PIONEER K88L1"] });
// If deviceNames and deviceSNs differ in length, the shorter is automatically padded with ""
Design Notes
- All timestamps use ms epoch. Timezone is captured per task at creation/update.
- Devices are deduplicated globally; many-to-many relation binds devices to per-path rows.
- CRUD on tasks cascades to paths and relations via FKs. Device master rows are retained
unless you explicitly garbage-collect unreferenced devices.
Methods
(static) hasJsExt(p) → {boolean}
Check whether a given path has a recognized JavaScript-like extension.
Supports .js, .tst, and .scp file types.
Example
hasJsExt("main.js"); // → true
hasJsExt("unit.tst"); // → true
hasJsExt("macro.scp"); // → true
hasJsExt("readme.txt"); // → false
Parameters:
| Name | Type | Description |
|---|---|---|
p |
string | The file path or name to check. |
Returns:
True if it ends with .js, .tst, or .scp (case-insensitive).
- Type
- boolean
(static) tasksChangeStatus(fromStatus, toStatus, optsopt) → {Object|false}
Change task status in bulk from one status to another.
Examples
// Example 1: Change all SCHEDULED (-6) tasks whose name contains "nightly" to RUNNING (-1)
tasksChangeStatus(STATUS.SCHEDULED, STATUS.RUNNING, {
nameLike: "nightly"
});
// Example 2: Pause specific tasks by mixed identifiers (row id, task_id, or task_name)
tasksChangeStatus(STATUS.RUNNING, STATUS.PAUSED, {
idsOrNames: [42, "9876543210", "daily_sync"]
});
// Example 3: Perform large updates in batches of 500 rows
let offset = 0, totalUpdated = 0;
while (true) {
const r = tasksChangeStatus(STATUS.SCHEDULED, STATUS.FILE_NOT_FOUND, {
limit: 500,
offset
});
if (!r || r.matched === 0) break;
totalUpdated += r.updated;
offset += 500;
}
console.log("Total updated rows:", totalUpdated);
// Example 4: No-op when fromStatus and toStatus are the same
// => returns { matched: 0, updated: 0, ids: [] }
tasksChangeStatus(STATUS.PAUSED, STATUS.PAUSED);
Parameters:
| Name | Type | Attributes | Description | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
fromStatus |
number | Only tasks currently with this status will be updated. |
|||||||||||||||||||||
toStatus |
number | The new status value to set. |
|||||||||||||||||||||
opts |
Object |
<optional> |
Optional filter options. Properties
|
Returns:
Returns statistics about the operation.
- Type
- Object | false
(static) tasksCount(filtersopt) → {object}
Count tasks (total and grouped by status), applying the same filters used by
tasksList()/tasksSearch() except pagination/sorting.
Supported filters:
- query: OR-group on task_name/error_message/exec_device/status-as-text
- nameLike: LIKE on task_name
- status: single or multipled
- endTimeOn: local-day filter on end_time (no range), optionally including NULL
Examples
// Count everything
var { total, byStatus } = tasksCount();
// Count only RUNNING and SCHEDULED on a specific local day
var res = tasksCount({
status: [STATUS.RUNNING, STATUS.SCHEDULED],
endTimeOn: "2025-09-15"
});
// res.total -> total rows whose status ∈ {-1,-6} on that day
Parameters:
| Name | Type | Attributes | Description | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
filters |
object |
<optional> |
Properties
|
Returns:
- { total:number, byStatus: Record<string, number> }
- Type
- object
(static) tasksCreate(name, scriptFile, iterationopt, timeopt, repeatopt) → {boolean|null}
Create and persist a new task.
Semantics
- Uniqueness:
taskNamemust be unique; returns false if already exists. - Script path: Must exist (JVM environment) and end with
.js | .tst | .scp; otherwise false. - Iteration: Defaults to
1when not provided; must be>=1, else false. - Repeat:
- If
repeatprovided and non-empty →timemust be"HH:mm"(if omitted,"00:00"is assumed). - If
repeatomitted/empty →timemust be"YYYY-MM-DD HH:mm[:ss]"(or omitted to mean "now").
- If
- planTime: Computed by computePlanTimeMs. Invalid parsing yields false.
- status: Initialized to module:sigma/tasks.STATUS.SCHEDULED (
-6).
Example
// Repeat every Mon & Wed at 00:00 local time:
var tid = tasksCreate("close huawei camera", "C:\\scripts\\close-huawei-camera.js", undefined, undefined, [1,3]);
// One-shot at a fixed datetime:
var tid2 = tasksCreate("one-shot", "E:\\File\\test.js", 2, "2025-09-01 08:00");
// One-time task with seconds
var tid3 = tasks.tasksCreate("one-shot-with-seconds", "E:\\File\\test.js", 1, "2025-09-01 08:01:20");
// Weekly task with seconds (if repeat supports seconds)
var today = (new Date()).getDay();
var tid4 = tasks.tasksCreate("weekly-with-seconds", "E:\\File\\test.js", 1, "08:01:20", [today, (today + 2) % 7]);
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
name |
string | Unique task name (non-empty). |
||
scriptFile |
string | Absolute path to a |
||
iteration |
number |
<optional> |
1
|
Number of planned executions (>=1). |
time |
string |
<optional> |
Repeat: |
|
repeat |
Array.<(number|string)> |
<optional> |
Weekdays |
Returns:
- Simplified form (name, scriptFile, ...): true on success, false on failure. and the specific error message is obtained by the lastError() function. null is only used for invalid inputs in certain environments.
- Type
- boolean | null
(static) tasksCreateMany(items, optsopt) → {object}
Create many tasks in batch.
Two operation modes:
- Non-atomic (default): Create one by one. Failures don't roll back successes.
- Use when you want "best-effort" creation (some may succeed, some may fail).
- Atomic ({ atomic: true }): Attempt to create all inside a single transaction.
- If ANY item fails, the whole batch is considered failed (rolled back).
- NOTE: This implementation delegates to
tasksCreate()which starts
its own transactions. Depending on your driver, nested transactions
may not be truly atomic at the DB level. The returned shape still
reflects "all-or-nothing" intent. If you require strict DB-level
atomicity, consider refactoringtasksCreate()to accept an
external connection and use a single outer transaction here.
Input item shapes accepted (each element of items array):
- Simplified: { name, scriptFile, iteration?, time?, repeat?, ... }
- Full: { taskName, scriptFile? | options?, iteration?/iterCount?, time?, repeat?, ... }
Return value:
{
results: Array<{ index:number, input:Object, code:(boolean|number) }>,
created: number, // count of successfully created
failed: number // count of failed
}
- Non-atomic:
codeis the raw return fromtasksCreate()per item (true/false or taskID number). - Atomic:
codeis true on each item iff the whole batch succeeded; false for all if rolled back.
Example
// 1) Non-atomic: expect partial success
var r1 = tasksCreateMany([
{ name: "cm_ok1", scriptFile: "C:/a.js" },
{ name: "cm_dup", scriptFile: "C:/a.js" }, // duplicate on purpose
{ name: "cm_ok2", scriptFile: "C:/a.js" }
], { atomic: false });
// r1.created >= 1 and r1.failed >= 1
// 2) Atomic: duplicate causes whole batch to fail
var r2 = tasksCreateMany([
{ name: "cm_ok1", scriptFile: "C:/a.js" },
{ name: "cm_dup", scriptFile: "C:/a.js" }, // duplicate
{ name: "cm_ok2", scriptFile: "C:/a.js" }
], { atomic: true });
// r2.created === 0, r2.failed === 3
// 3) Mixed shapes are fine
var r3 = tasksCreateMany([
{ name: "jobA", scriptFile: "C:/a.js", time: "2025-12-01 08:00" }, // simplified
{
taskName: "jobB", // full
options: [
{ path: "C:/x.js", device_names:["P40"], device_sn:["XYZ"] }
],
iteration: 1,
repeat: [1,3,5],
time: "08:30"
}
]);
tasksCreateMany([
{ name:"jobA", scriptFile:"C:\\a.js", repeat:[1,3], time:"08:00" },
{ name:"jobB", scriptFile:"C:\\b.js", iteration:2, time:"2025-09-01 08:00" }
]);
tasksCreateMany(
[{ name:"A", scriptFile:"C:\\a.js" }, { name:"B", scriptFile:"C:\\b.js"}],
{ atomic: true }
);
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
items |
Array | ||
opts |
boolean |
<optional> |
Returns:
- {results:Array<{index:number,input:Object,code:(boolean|number)}>,created:number,failed:number}
- Type
- object
(static) tasksDelete(idOrName) → {boolean}
Delete a task by id, taskID, or taskName. (cascade to paths & relations via FK).
Example
tasksDelete("nightly-sync");
tasksDelete(12); // row id
tasksDelete("1000234"); // taskID (string-numeric)
Parameters:
| Name | Type | Description |
|---|---|---|
idOrName |
number | string |
Returns:
true if one or more rows were deleted; false otherwise. and the specific error message is obtained by the lastError() function.
- Type
- boolean
(static) tasksDeleteMany(idsOrNames, optsopt) → {Object}
Delete many tasks in batch.
- Each id/name is deleted independently, default non-atomic (one missing does not affect others).
- If “all-or-nothing” is required, pass { atomic:true }. Any failure
(in practice, only lock or SQL errors can cause failure)
will cause full rollback.
Note: duplicate keys are still treated as separate deletion attempts.
Example
var out = tasksDeleteMany(["nightly", 12, "1002001"]);
// or
var out = tasksDeleteMany(["nightly", 12, "1002001"], { atomic: true });
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
idsOrNames |
Array.<(number|string)> | ||
opts |
Object |
<optional> |
Returns:
- Type
- Object
(static) tasksExists(name) → {boolean}
Check if a task with given taskName exists.
Example
if (tasksExists("nightly")) print("exists");
Parameters:
| Name | Type | Description |
|---|---|---|
name |
string | Task name |
Returns:
true if exists, false otherwise
- Type
- boolean
(static) tasksGet(idOrName) → {Object|null}
Get a single task by id / taskID / taskName (JOIN once and aggregate options).
Example
tasksGet("nightly"); // by taskName
tasksGet(42); // by row id
tasksGet("1759213730566"); // by taskID (string)
Parameters:
| Name | Type | Description |
|---|---|---|
idOrName |
number | string |
Returns:
Aggregated task or null if not found
- Type
- Object | null
(static) tasksList(filtersopt) → {Array.<Object>}
List tasks with optional filters and ordering.
Performs task-level pagination by first selecting t.id then JOINing child tables.
Filters:
- status:
- Accepts a single value or multiple values.
- Type:
number | string | Array<number|string>
- nameLike: SQL LIKE match on
task_name(properly escapes%and_usingESCAPE '\'). - endTimeOn: Filter rows whose
end_timefalls on the given local day (00:00:00.000 ~ 23:59:59.999).- Type:
string | number | Date(recommend'YYYY-MM-DD'). includeNullEndTime: when true, also include rows withend_time IS NULL.
- Type:
Pagination/ordering:
- limit/offset: Task-level pagination (applied on task row ids).
- orderBy: Whitelisted/controlled by caller. Default:
"t.updated_at DESC".
Returned shape:
- Aggregated tasks with
options: [{ path, device_names, device_sn }, ...]
Example
// 1) All tasks (no filters)
tasksList();
// 2) Multiple status on a specific local day
tasksList({
status: [STATUS.SCHEDULED, STATUS.RUNNING],
endTimeOn: "2025-09-15",
limit: 50
});
// 3) Single status on a specific local day
tasksList({ status: STATUS.SCHEDULED, endTimeOn: "2025-09-15", limit: 20 });
// 4) LIKE on task_name
tasksList({ nameLike: "promo_50%_off" }); // literal '%' and '_' supported
Parameters:
| Name | Type | Attributes | Description | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
filters |
object |
<optional> |
Properties
|
Returns:
Aggregated tasks
- Type
- Array.<Object>
(static) tasksPause(name) → {boolean|null}
Pause the tasks based on the task name.
Example
// Example: Create a task, wait for 5 seconds, then pause it.
var { tasksCreate, tasksPause } = require("sigma/tasks");
var task001 = tasksCreate('task001', 'E:/File/test.js', 1);
if (task001 === true) {
delay(5000);
var ret = tasksPause('task001');
if (ret === true) {
print("Congratulations, this API executes successfully.\nReturn value: " + ret);
} else {
print("Sorry! " + lastError() + "\nReturn value: " + ret);
}
} else {
print(lastError());
}
// If successful, the output will be:
Congratulations, this API executes successfully.
Return value: true
// If failed:
Sorry! <error message>
Return value: false
Parameters:
| Name | Type | Description |
|---|---|---|
name |
String | The name of the tasks |
Returns:
Returns true if successful, false if it fails, and the specific error message is obtained by the lastError() function.
- Type
- boolean | null
(static) tasksReset(confirm)
Drop and recreate the tasks table (irreversible).
Danger zone: clears all data.
Example
// Development only:
tasksReset(true);
Parameters:
| Name | Type | Description |
|---|---|---|
confirm |
boolean | Must be |
Throws:
-
If
confirm !== true. - Type
- Error
(static) tasksResume(name) → {boolean|null}
Resume the tasks based on the task name.
Example
// Example: Create a task, pause it, then resume it.
var { tasksCreate, tasksPause, tasksResume } = require("sigma/tasks");
var tasksCreate = tasksCreate('task001', 'E:/File/test.js', 1);
if (tasksCreate === true) {
delay(5000);
var tasksPause = tasksPause('task001');
var tasksResume = tasksResume('task001');
if (tasksPause === true && tasksResume === true) {
print("Congratulations, this API executes successfully.\nReturn value: " + taskResume);
} else {
print("Sorry! " + lastError() + "\nReturn value: " + taskResume);
}
} else {
print(lastError());
}
// If successful, the output will be:
Congratulations, this API executes successfully.
Return value: true
// If failed:
Sorry! <error message>
Return value: false
Parameters:
| Name | Type | Description |
|---|---|---|
name |
String | The name of the tasks. |
Returns:
Returns true if successful, false if it fails, and the specific error message is obtained by the lastError() function.
- Type
- boolean | null
(static) tasksSearch(query, optsopt) → {Array.<Object>}
Full-text-ish search on key columns using SQL LIKE.
Matches against: task_name, error_message, exec_device, and status (as text).
Uses a single JOIN and aggregates options.
Optional status filtering:
- status:
- Accepts a single value or multiple values.
- Type:
number | string | Array<number|string>
Optional end-time-on-day filter:
- endTimeOn: Filter rows whose
end_timefalls on the given local day (no range). - includeNullEndTime: Include
end_time IS NULLrows when present.
Example
// 1) Basic text search
tasksSearch("camera"); // by name/content
// 2) Search within certain status on a local day
tasksSearch("device-XYZ", {
status: [STATUS.SCHEDULED, STATUS.RUNNING],
endTimeOn: "2025-09-15",
limit: 10
});
// 3) by status string
tasksSearch(String(STATUS.SCHEDULED), { limit: 10 });
tasksSearch("device-XYZ", { limit: 10 });
Parameters:
| Name | Type | Attributes | Description | |||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
query |
string | Non-empty search string (raw; escaping handled internally) |
||||||||||||||||||||||||||||||||||||
opts |
object |
<optional> |
Properties
|
Returns:
Aggregated tasks
- Type
- Array.<Object>
(static) tasksStop(name) → {boolean|null}
Stop the tasks based on the task name.
Example
// Example: Create a task, wait 5 seconds, then stop it.
var { tasksCreate, tasksStop} = require("sigma/tasks");
var tasksCreate = tasksCreate('task001', 'E:/File/test.js', 1);
if (tasksCreate === true) {
delay(5000);
var tasksStop = tasksStop('task001');
if (tasksStop === true) {
print("Congratulations, this API executes successfully.\nReturn value: " + taskStop);
} else {
print("Sorry! " + lastError() + "\nReturn value: " + taskStop);
}
} else {
print(lastError());
}
// If successful:
Congratulations, this API executes successfully.
Return value: true
// If failed:
Sorry! <error message>
Return value: false
Parameters:
| Name | Type | Description |
|---|---|---|
name |
String | The name of the tasks. |
Returns:
Returns true if successful, false if it fails, and the specific error message is obtained by the lastError() function.
- Type
- boolean | null
(static) tasksUpdate(idOrName, patch) → {boolean|null}
Partially update a task. Supports "repeat" + "time" constraints:
- When patch includes
repeat:- It is normalized and stored as
weekJson. - If patch also includes
timeorrepeatis non-empty,timemust be"HH:mm[:ss]"(or omitted →"00:00"). planTimeis recomputed accordingly.
- It is normalized and stored as
- When patch includes
timewithoutrepeat:timemust be"YYYY-MM-DD HH:mm[:ss]".planTimeis set accordingly.
Name Uniqueness
- If patch includes
taskName, it must be non-empty and unique (excluding the current row).
Example
// Update name:
tasksUpdate("nightly", { taskName: "nightly-v2" });
// Switch to weekly repeat (Mon-Fri) at 08:30:
tasksUpdate("nightly-v2", { repeat: [1,2,3,4,5], time: "08:30" });
// One-shot reschedule: row id
tasksUpdate(15, { time: "2025-12-01 10:00" });
// taskID
tasksUpdate("1756350622382", { time: "2025-12-01 10:00" });
Parameters:
| Name | Type | Description |
|---|---|---|
idOrName |
number | string |
|
patch |
object | Allowed keys:
|
Returns:
- true on successful update, null if the target task does not exist.
- Type
- boolean | null