mirror of
https://github.com/lancedb/lancedb.git
synced 2026-09-01 19:18:38 +00:00
b0dae5eb0b
## Problem `refresh_column_async` returned a unit-result job even though durable refresh jobs carry a canonical terminal result. Python callers could not obtain row counts or source and published versions through the public `Job` API, and local and remote refresh jobs exposed different result semantics. ## Behavior `refresh_column_async` now returns `Job[RefreshColumnResult]` for local and remote tables. The general typed-job bridge binds each endpoint to its public result model while preserving unit-result jobs and existing status, wait, cancel, and timeout behavior. A local no-op refresh reports no published version. The Node.js API continues to resolve `wait()` as `void`; its binding erases the Rust result type internally to preserve the existing public contract. ## Ownership and integration boundary LanceDB owns the language-neutral `Job<T>` contract and language-binding decode. Sophon owns production and durable persistence of terminal payloads. Sophon #7348 and #7378 now publish the canonical refresh result for Function-backed and expression-backed refresh jobs, respectively. The remote client fixture matches the merged server schema; live deployment and end-to-end demo acceptance remain separate rollout checks.
127 lines
3.8 KiB
Rust
127 lines
3.8 KiB
Rust
// SPDX-License-Identifier: Apache-2.0
|
|
// SPDX-FileCopyrightText: Copyright The LanceDB Authors
|
|
|
|
use std::sync::Arc;
|
|
|
|
use napi_derive::napi;
|
|
|
|
use crate::error::NapiErrorExt;
|
|
|
|
/// A handle to an operation that may still be running.
|
|
#[napi]
|
|
pub struct Job {
|
|
inner: Arc<lancedb::Job>,
|
|
}
|
|
|
|
impl Job {
|
|
pub(crate) fn new<T>(inner: lancedb::Job<T>) -> Self
|
|
where
|
|
T: Clone + Send + Sync + 'static,
|
|
{
|
|
Self {
|
|
inner: Arc::new(inner.map(|_| ())),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[napi]
|
|
impl Job {
|
|
/// Identifies the operation on the server that is running it. Operations
|
|
/// that run in this process have no server id. The value is opaque.
|
|
#[napi(getter)]
|
|
pub fn id(&self) -> Option<String> {
|
|
self.inner.id().map(str::to_string)
|
|
}
|
|
|
|
/// The operation's current lifecycle state: "running", "finished",
|
|
/// "failed", or "cancelled".
|
|
///
|
|
/// A point snapshot; unlike {@link Job.wait} it does not block or reject
|
|
/// on a terminal failure state. States a newer server reports that this
|
|
/// client version does not know pass through as-is.
|
|
#[napi(catch_unwind)]
|
|
pub async fn status(&self) -> napi::Result<String> {
|
|
self.inner.status().await.default_error()
|
|
}
|
|
|
|
/// Wait until the operation reaches a terminal state.
|
|
#[napi(catch_unwind)]
|
|
pub async fn wait(&self) -> napi::Result<()> {
|
|
self.inner.wait().await.default_error()
|
|
}
|
|
|
|
/// Request cancellation. Cancelling a finished operation is a no-op.
|
|
#[napi(catch_unwind)]
|
|
pub async fn cancel(&self) -> napi::Result<()> {
|
|
self.inner.cancel().await.default_error()
|
|
}
|
|
}
|
|
|
|
/// A row from `Connection.listJobs`: one server-side job.
|
|
#[napi(object)]
|
|
pub struct JobInfo {
|
|
/// The job id -- what `Connection.getJob` and `Connection.cancelJob`
|
|
/// accept.
|
|
pub job_id: String,
|
|
/// The table the job runs against, without URI or namespace.
|
|
pub table: String,
|
|
pub job_type: String,
|
|
/// Lifecycle state: "running", "finished", "failed", or "cancelled".
|
|
pub state: String,
|
|
/// When the job was created, in milliseconds since the epoch.
|
|
pub created_at_millis: i64,
|
|
}
|
|
|
|
impl From<lancedb::database::JobInfo> for JobInfo {
|
|
fn from(info: lancedb::database::JobInfo) -> Self {
|
|
Self {
|
|
job_id: info.job_id,
|
|
table: info.table,
|
|
job_type: info.job_type,
|
|
state: info.state,
|
|
created_at_millis: info.created_at_millis,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The server's account of why a job failed.
|
|
#[napi(object)]
|
|
pub struct JobFailureInfo {
|
|
pub phase: Option<String>,
|
|
pub message: Option<String>,
|
|
pub retryable: Option<bool>,
|
|
}
|
|
|
|
/// A described job from `Connection.getJob`.
|
|
#[napi(object)]
|
|
pub struct JobDescription {
|
|
pub job_id: String,
|
|
pub job_type: String,
|
|
/// Lifecycle state: "running", "finished", "failed", or "cancelled".
|
|
pub state: String,
|
|
/// When the job was created, in milliseconds since the epoch.
|
|
pub creation_ms: i64,
|
|
/// The job-type-specific specification as a JSON string, when present.
|
|
pub spec_json: Option<String>,
|
|
/// Why the job failed, when the job is failed and the server reports a
|
|
/// reason.
|
|
pub failure: Option<JobFailureInfo>,
|
|
}
|
|
|
|
impl From<lancedb::database::JobDescription> for JobDescription {
|
|
fn from(description: lancedb::database::JobDescription) -> Self {
|
|
Self {
|
|
job_id: description.job_id,
|
|
job_type: description.job_type,
|
|
state: description.state,
|
|
creation_ms: description.creation_ms,
|
|
spec_json: (!description.spec.is_null()).then(|| description.spec.to_string()),
|
|
failure: description.failure.map(|failure| JobFailureInfo {
|
|
phase: failure.phase,
|
|
message: failure.message,
|
|
retryable: failure.retryable,
|
|
}),
|
|
}
|
|
}
|
|
}
|