News & Updates

Async Operations With The Databricks Python SDK Guide

By Spencer Vaughn 10 min read 1317 views

Async Operations With The Databricks Python SDK Guide

When you start juggling large data pipelines on Databricks, the temptation to fire off everything at once is strong. The Databricks Python SDK actually gives you a clean way to run jobs asynchronously, so you can keep your notebook responsive and your cluster humming without waiting for each step to finish.

Why Go Async?

Running a job synchronously means your code blocks until the cluster reports success or failure. In a production notebook that could mean minutes—or hours—of idle time. Asynchronous calls free the thread, let you launch multiple jobs, poll status later, or even spin up other tasks while you wait.

Getting Started: The Basic Setup

First things first: you need a Databricks workspace and a personal access token. Install the SDK with a single pip line, then import the client.

  • pip install databricks-sdk
  • from databricks.sdk import WorkspaceClient

When you instantiate WorkspaceClient, pass in the token and the URL of your workspace. Nothing fancy, but remember to keep the token out of source control.

Sample Initialization

client = WorkspaceClient(

host="https://adb-1234567890123456.17.azuredatabricks.net",

token="dapiXXXXXXXXXXXXXXXXXXXXXXXX"

)

That object now holds methods for jobs, clusters, and DBFS—everything you need to start an async workflow.

Launching a Job Asynchronously

The SDK exposes client.jobs.submit_run. By default it returns a Run object and blocks until the run finishes. To make it async, add the async_req=True flag. The method immediately returns a Future‑like handle you can inspect later.

future = client.jobs.submit_run(

run_name="daily_aggregation",

existing_cluster_id="0923-123456-abcde",

notebook_task={"notebook_path": "/Users/me/aggregate"},

async_req=True

)

The future object contains a run_id. Store that somewhere—perhaps in a tiny SQLite DB—so you can retrieve status after a coffee break.

Polling for Completion

Databricks doesn’t push notifications, so you’ll need to poll. A simple loop with exponential back‑off does the trick without hammering the API.

import time

run_id = future.run_id

delay = 5

while True:

status = client.runs.get(run_id).state.life_cycle_state

if status in ("TERMINATED", "SKIPPED", "INTERNAL_ERROR"):

break

time.sleep(delay)

delay = min(delay * 2, 60) # cap at 1 minute

When the loop exits, you can fetch the final result or error logs.

Running Multiple Jobs in Parallel

Imagine you have to refresh three independent dashboards each morning. With async calls you can launch all three and then wait for all to finish, rather than chaining them sequentially.

jobs = ["dash_a", "dash_b", "dash_c"]

futures = []

for job in jobs:

futures.append(

client.jobs.submit_run(

run_name=f"{job}_refresh",

existing_cluster_id="0923-123456-abcde",

notebook_task={"notebook_path": f"/Users/me/{job}"},

async_req=True

)

)

# Wait for every future

for fut in futures:

# Simple poll as before, or use concurrent.futures.as_completed

pass

Because each submit is non‑blocking, the total wall‑clock time drops dramatically, limited only by cluster capacity.

Handling Errors Gracefully

Async doesn’t mean “ignore errors.” The Future object may raise an exception when you finally request the result. Wrap the final status check in a try/except block, and consider logging the run_id for later analysis.

try:

result = client.runs.get(run_id)

if result.state.result_state != "SUCCESS":

raise RuntimeError(f"Run {run_id} failed")

except Exception as e:

logger.error(f"Async job {run_id} error: {e}")

This pattern keeps your notebook tidy and your monitoring scripts happy.

Best‑Practice Checklist

  • Keep tokens secure. Use environment variables or secret scopes.
  • Limit polling frequency. A 5‑10‑second pause is usually enough.
  • Don’t overload clusters. Respect your quota; submitting dozens of jobs at once can cause throttling.
  • Persist run IDs. Saves you from losing track if the notebook crashes.
  • Clean up after yourself. Optionally delete finished runs to keep the UI tidy.

Advanced Tip: Using Async With Python’s asyncio

If you’re comfortable with asyncio, you can wrap the SDK calls in coroutines. The SDK itself isn’t natively async, but you can run the blocking calls in an executor.

import asyncio

from concurrent.futures import ThreadPoolExecutor

executor = ThreadPoolExecutor(max_workers=5)

async def launch_job(name):

loop = asyncio.get_event_loop()

future = await loop.run_in_executor(

executor,

lambda: client.jobs.submit_run(

run_name=name,

existing_cluster_id="0923-123456-abcde",

notebook_task={"notebook_path": f"/Users/me/{name}"},

async_req=True

)

)

return future.run_id

async def main():

runs = await asyncio.gather(

launch_job("dash_x"),

launch_job("dash_y"),

launch_job("dash_z")

)

print("Launched runs:", runs)

asyncio.run(main())

This approach meshes nicely with other async I/O—think reading from a database or calling an external API—while still leveraging the Databricks SDK.

Wrapping Up

Async operations with the Databricks Python SDK aren’t a silver bullet, but they can shave off idle minutes and make your data engineering scripts feel a lot more responsive. Start small: fire off a single notebook, poll its status, and once you’ve got the rhythm, scale up to multiple parallel jobs or even an asyncio‑driven orchestrator. The payoff is usually worth the extra bit of plumbing.

Databricks Python SDK for Account Admins | by Ashley Johnson | Medium
The Databricks Python SDK. The Databricks SDK is a script (written ...
Introducing the Power of Databricks SDK - Speaker Deck
Mastering PySpark and Azure Databricks - Course - YouTube

Written by Spencer Vaughn

Spencer Vaughn is a Chief Correspondent with over a decade of experience covering breaking trends, in-depth analysis, and exclusive insights.