Skip to content

yggdrasil.databricks.job.run

run

Databricks JobRun resource — individual run lifecycle.

:class:JobRun implements :class:~yggdrasil.dataclasses.awaitable.Awaitable so callers can run.wait() / run.cancel() with the same backoff and timeout contract used by every other async surface in yggdrasil.

:class:JobTask is a thin read-only wrapper around :class:~databricks.sdk.service.jobs.RunTask for inspecting per-task state within a run.

JobRun

JobRun(
    service: JobRuns | None = None,
    run_id: "int | str | None" = None,
    job_id: "int | str | None" = None,
    *,
    details: Run | None = None,
    singleton_ttl: Any = ...
)

Bases: Singleton, DatabricksResource, Awaitable

Individual Databricks job run — awaitable lifecycle handle.

Parameters

service: Parent :class:JobRuns service. run_id: Databricks run id. Accepts int or numeric str. job_id: Owning job id. details: Pre-fetched SDK :class:~databricks.sdk.service.jobs.Run.

Positional construction::

JobRun(service, 98765)       # by run id
JobRun(service, "98765")     # numeric string → by run id

explore_url property

explore_url: URL

Workspace UI URL for this run (/jobs/<job_id>/runs/<run_id>).

Prefers the SDK-provided run_page_url when run details are already loaded — it carries the canonical workspace host and the owning job_id even for one-time submitted runs that have no job id of their own. Otherwise the URL is built from the client host, falling back to the jobs list page when job_id isn't known yet (e.g. a handle built from a run id before its first :meth:refresh).

stdout property

stdout: str

Every task's captured stdout, each section prefixed by its task key — a single string ready to print when debugging.

stderr property

stderr: str

Every failed task's error trace, each prefixed by its task key.

sql property

sql: 'SQLEngine'

Shorthand for self.service.client.sql — the active :class:SQLEngine.

task

task(key: str) -> 'JobTask | None'

The awaitable :class:JobTask for key, or None if absent.

run.task("ingest").wait() blocks until that single task reaches a terminal state (by polling this run).

dag

dag() -> 'JobDag'

The run's task graph with live per-task state — see :class:~yggdrasil.databricks.job.dag.JobDag.

results

results() -> dict[str, Any]

Best-effort per-task output: task_key → SDK RunOutput.

One get_run_output call per task run id; tasks whose output can't be fetched (no id yet, or an output-less task type) are simply omitted. The run must be waited on first for outputs to be meaningful.

task_output

task_output(key: str) -> Any | None

SDK RunOutput for the task key (or None).

logs

logs(task_key: str | None = None) -> Any

Captured console output. With task_key, that task's log text; without it, a {task_key: log text} map across all tasks (None entries for tasks with no fetchable output).

debug

debug() -> str

A human-readable dump — run state, the task DAG, and each task's state + stdout + stderr — for eyeballing or pasting into a bug report.

One get_run_output call per task, so call it on a terminal run.

repair

repair(
    *,
    rerun_tasks: list[str] | None = None,
    wait: WaitingConfigArg = False,
    raise_error: bool = True
) -> "JobRun"

Repair (rerun) failed tasks in this run.

Parameters

rerun_tasks: Task keys to rerun. None reruns all failed tasks. wait: Block until the repair finishes. raise_error: Raise on failure when waiting.

progress

progress() -> 'float | None'

A 0..1 completion fraction for a progress bar, or None if unknown.

A UI hook: a generic awaitable can't know its fraction, so the base returns None (drive a spinner, not a bar). Subclasses that do know — a batch's children done, a statement's rows fetched — override this. Consumed by :func:yggdrasil.cli.style.track.

watch

watch(
    on_tick: "Any" = None, *, interval: float = 0.1, raise_error: bool = True
) -> "Awaitable"

Drive to completion, calling on_tick(self) each poll.

The hook a UI (spinner / progress bar) connects to without this trait importing any UI — keeping the layering clean. Starts the awaitable if it hasn't been, polls until done, then surfaces a failure (unless raise_error is False). Pairs with :func:yggdrasil.cli.style.track.

to_singleton

to_singleton(ttl: Any = ...) -> 'Singleton'

Promote this instance into the per-class _INSTANCES cache.

Hot listing paths (iterdir / _ls / glob) build children with singleton_ttl=False so the bounded cache doesn't fill up with thousands of short-lived entries. When a caller decides one of those children is worth keeping around (handing it to a long-running worker, returning it from an API), :meth:to_singleton registers self into the cache so the next constructor call with the same key collapses to the same instance.

ttl defaults to the subclass's _SINGLETON_TTL (... = no caching, None = process lifetime, or a seconds count). When a different instance is already cached under this key, that pre-existing one wins and is returned unchanged — the cache is the source of truth.

invalidate_singleton

invalidate_singleton(remove_global: bool = True) -> None

Pop self from the per-class _INSTANCES cache.

Mutating ops on a Singleton-cached object (writes, deletes, schema invalidations on a Databricks table, put_object on an :class:S3Path) want to make sure the next caller asking for the same key gets a fresh build rather than collapsing onto this stale handle — that's what remove_global=True (the default) does. The pop is :meth:identity-guarded: only an entry that still points at self is removed, so a concurrent re-construction that already raced past this thread is left alone.

remove_global=False is a no-op. The keyword exists so subclass invalidators (invalidate_singleton, _invalidate_entity_tag_cache, …) can offer the same switch without branching at the call site.

JobTask

JobTask(raw: RunTask, run: 'JobRun | None' = None)

Bases: Awaitable

A single task within a job run — an awaitable handle.

Built from a run's task list with a back-reference to the parent :class:JobRun, so :meth:wait (the :class:Awaitable contract) polls the run until this task reaches a terminal state. Constructed without a parent (run=None) it's a static read-only snapshot of the task at build time.

The is_done / is_succeeded / is_failed / wait / cancel surface comes from :class:Awaitable; :attr:state tracks the last polled task state. A task can't be cancelled in isolation — :meth:_cancel cancels the whole parent run.

run property

run: 'JobRun | None'

The parent run this task belongs to (None for a snapshot).

run_id property

run_id: int | None

This task's own run id (used to fetch its output).

logs property

logs: str | None

Captured console output (Databricks merges stdout + stderr into one logs stream). None when unavailable.

stderr property

stderr: str | None

The failure detail — the error traceback, falling back to the error message. None for a task that didn't error.

error_message property

error_message: str | None

Short error message for a failed task (no traceback).

output

output() -> Any | None

SDK RunOutput for this task's run (logs / error / notebook result), or None when there's no parent run or run id yet, or the task type produces no fetchable output.

progress

progress() -> 'float | None'

A 0..1 completion fraction for a progress bar, or None if unknown.

A UI hook: a generic awaitable can't know its fraction, so the base returns None (drive a spinner, not a bar). Subclasses that do know — a batch's children done, a statement's rows fetched — override this. Consumed by :func:yggdrasil.cli.style.track.

watch

watch(
    on_tick: "Any" = None, *, interval: float = 0.1, raise_error: bool = True
) -> "Awaitable"

Drive to completion, calling on_tick(self) each poll.

The hook a UI (spinner / progress bar) connects to without this trait importing any UI — keeping the layering clean. Starts the awaitable if it hasn't been, polls until done, then surfaces a failure (unless raise_error is False). Pairs with :func:yggdrasil.cli.style.track.