feat(nodejs): pause and resume jobs from the TypeScript SDK

Companion to the Python surface: pauseJob and resumeJob on Connection,
posting to the server's /v1/jobs/pause and /v1/jobs/resume endpoints. A
pause parks the job until it is resumed: its workers drain and stop, and
a resume re-queues it to pick work back up from checkpoints.

The outcome strings mirror the server's answers -- "pausing",
"already_paused", or "committing" (a job finalizing its results cannot
be parked; retry shortly), and "resumed", "still_pausing", or
"not_paused" -- so a caller can retry the transient refusals rather
than treat them as failures.
This commit is contained in:
Wyatt Alt
2026-09-01 13:28:57 +00:00
parent d82fe8520f
commit b0f010ad83
3 changed files with 73 additions and 0 deletions
+19
View File
@@ -987,6 +987,22 @@ describe("remote connection jobs surface", () => {
res
.writeHead(200, { "Content-Type": "application/json" })
.end('{"job_id": "job-1"}');
} else if (req.url === "/v1/jobs/pause") {
if (payload["job_id"] !== "job-1") {
res.writeHead(404).end("no such job");
return;
}
res
.writeHead(200, { "Content-Type": "application/json" })
.end('{"job_id": "job-1", "paused": true}');
} else if (req.url === "/v1/jobs/resume") {
if (payload["job_id"] !== "job-1") {
res.writeHead(404).end("no such job");
return;
}
res
.writeHead(200, { "Content-Type": "application/json" })
.end('{"job_id": "job-1", "resumed": false, "still_pausing": true}');
} else if (req.url === "/v1/jobs/query_events") {
res
.writeHead(200, {
@@ -1015,6 +1031,9 @@ describe("remote connection jobs surface", () => {
expect(await db.cancelJob("job-1")).toBe(true);
expect(await db.cancelJob("missing")).toBe(false);
expect(await db.pauseJob("job-1")).toEqual("pausing");
expect(await db.resumeJob("job-1")).toEqual("still_pausing");
const history = await db.jobHistory("job-1");
expect(history.numRows).toEqual(2);
+26
View File
@@ -583,6 +583,24 @@ export abstract class Connection {
*/
abstract cancelJob(jobId: string): Promise<boolean>;
/**
* Pause a server-side job by id.
*
* The job's workers drain and it stays parked until resumed. Resolves to
* "pausing", "already_paused", or "committing" -- a job finalizing its
* results cannot be parked; retry shortly.
*/
abstract pauseJob(jobId: string): Promise<string>;
/**
* Resume a paused server-side job by id.
*
* Its workers pick their work back up from checkpoints. Resolves to
* "resumed", "still_pausing" -- the pause's worker drain is not confirmed
* yet; retry shortly -- or "not_paused".
*/
abstract resumeJob(jobId: string): Promise<string>;
/**
* The lifecycle event history of a server-side job, as an Arrow table.
*
@@ -944,6 +962,14 @@ export class LocalConnection extends Connection {
return this.inner.cancelJob(jobId);
}
async pauseJob(jobId: string): Promise<string> {
return this.inner.pauseJob(jobId);
}
async resumeJob(jobId: string): Promise<string> {
return this.inner.resumeJob(jobId);
}
async jobHistory(jobId?: string): Promise<ArrowTable> {
const buf = await this.inner.jobHistory(jobId);
if (buf.length === 0) {
+28
View File
@@ -477,6 +477,34 @@ impl Connection {
self.get_inner()?.cancel_job(&job_id).await.default_error()
}
/// Pause a server-side job by id: its workers drain and it stays parked
/// until resumed. Returns "pausing", "already_paused", or "committing".
#[napi(catch_unwind)]
pub async fn pause_job(&self, job_id: String) -> napi::Result<String> {
let status = self.get_inner()?.pause_job(&job_id).await.default_error()?;
Ok(match status {
lancedb::database::PauseJobStatus::Pausing => "pausing".to_string(),
lancedb::database::PauseJobStatus::AlreadyPaused => "already_paused".to_string(),
lancedb::database::PauseJobStatus::Committing => "committing".to_string(),
})
}
/// Resume a paused server-side job by id. Returns "resumed",
/// "still_pausing", or "not_paused".
#[napi(catch_unwind)]
pub async fn resume_job(&self, job_id: String) -> napi::Result<String> {
let status = self
.get_inner()?
.resume_job(&job_id)
.await
.default_error()?;
Ok(match status {
lancedb::database::ResumeJobStatus::Resumed => "resumed".to_string(),
lancedb::database::ResumeJobStatus::StillPausing => "still_pausing".to_string(),
lancedb::database::ResumeJobStatus::NotPaused => "not_paused".to_string(),
})
}
/// The lifecycle event history of a server-side job (all jobs when
/// `job_id` is null), as an Arrow IPC stream buffer. Empty when there is
/// no history.