Skip to content

Commit 0bc6448

Browse files
feat(dgw): record provisioner tasks in gateway.db
A Task is the permanent record of work the provisioner asked Gateway to do: its kind, target and parameters, its state and a payload the kind defines. The work itself will run as a job on the job queue, which forgets it once done; the Task stays for status and auditing. The provisioner chooses the Task ID, so asking again with the same request returns the existing Task. At most one unfinished Task works on a target per kind, and a Task past its deadline is failed when another one asks for its target, so a lost job never blocks it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 01d41dc commit 0bc6448

7 files changed

Lines changed: 667 additions & 0 deletions

File tree

‎Cargo.lock‎

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎crates/gateway-db/Cargo.toml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ anyhow = "1"
1414
async-trait = "0.1"
1515
camino = "1.1"
1616
libsql = { version = "0.9", default-features = false, features = ["core", "serde"] }
17+
provisioner-task.path = "../provisioner-task"
18+
serde_json = "1"
19+
time = { version = "0.3", default-features = false }
1720
tokio = { version = "1.52", features = ["sync"] }
1821
tracing = "0.1"
1922
uuid = "1.23"
2023

2124
[dev-dependencies]
2225
tempfile = "3.24"
2326
tokio = { version = "1.52", features = ["macros", "rt-multi-thread"] }
27+
uuid = { version = "1.23", features = ["v4"] }
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
CREATE TABLE provisioner_task (
2+
id TEXT PRIMARY KEY,
3+
kind TEXT NOT NULL,
4+
target TEXT NOT NULL,
5+
params TEXT NOT NULL,
6+
state TEXT NOT NULL,
7+
payload TEXT NOT NULL,
8+
attempts INTEGER NOT NULL DEFAULT 0,
9+
created_at INTEGER NOT NULL,
10+
started_at INTEGER,
11+
finished_at INTEGER,
12+
deadline_at INTEGER NOT NULL,
13+
CHECK (state IN ('queued', 'running', 'succeeded', 'failed')),
14+
CHECK ((state IN ('succeeded', 'failed')) = (finished_at IS NOT NULL)),
15+
CHECK (json_valid(params) AND json_valid(payload)),
16+
CHECK (attempts >= 0)
17+
);
18+
19+
CREATE UNIQUE INDEX provisioner_task_unfinished ON provisioner_task (kind, target)
20+
WHERE state IN ('queued', 'running');

‎crates/gateway-db/src/lib.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
extern crate tracing;
1010

1111
pub mod agent_tunnel;
12+
pub mod provisioner_task;
1213

1314
use anyhow::{Context as _, bail};
1415
use camino::{Utf8Path, Utf8PathBuf};
@@ -31,6 +32,7 @@ const PRAGMAS: &str = "
3132
const MIGRATIONS: &[&str] = &[
3233
include_str!("../migrations/01_agent_tunnel.sql"),
3334
include_str!("../migrations/02_prefix_agent_tunnel_tables.sql"),
35+
include_str!("../migrations/03_provisioner_task.sql"),
3436
];
3537

3638
/// The open `gateway.db`, ready to hand a connection to each feature that keeps tables in it.
@@ -250,6 +252,7 @@ mod tests {
250252
assert!(table_exists(&conn, "agent_tunnel_accepted_agents").await);
251253
assert!(table_exists(&conn, "agent_tunnel_enrollment_attempts").await);
252254
assert!(table_exists(&conn, "agent_tunnel_deleted_agent_keys").await);
255+
assert!(table_exists(&conn, "provisioner_task").await);
253256
assert!(!table_exists(&conn, "metadata").await);
254257
}
255258

0 commit comments

Comments
 (0)