Async Jobs
Handle long-running operations with async jobs
Async Jobs
For long-running operations like video and music generation, use async mode to avoid timeouts and provide better user experience.
When to Use Async
Use async mode for:
- Video generation (30-120 seconds)
- Music generation (30-60 seconds)
- High-resolution image generation
- Batch operations
Workflow
1. Submit request with ?async=true
2. Receive job ID immediately
3. Poll /jobs/{id} for status
4. Retrieve result when completeImplementation
import requests
import time
class AsyncJobHandler:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = "https://www.novakit.ai/api/v1"
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def submit_job(self, endpoint, data):
"""Submit an async job and return job ID."""
response = requests.post(
f"{self.base_url}/{endpoint}?async=true",
headers=self.headers,
json=data
)
response.raise_for_status()
return response.json()["id"]
def poll_job(self, job_id, interval=5, timeout=300):
"""Poll job until completion or timeout."""
start_time = time.time()
while time.time() - start_time < timeout:
response = requests.get(
f"{self.base_url}/jobs/{job_id}?poll=true",
headers=self.headers
)
response.raise_for_status()
status = response.json()
if status["status"] == "completed":
return status
if status["status"] == "failed":
raise Exception(f"Job failed: {status.get('errorMessage')}")
if status["status"] == "cancelled":
raise Exception("Job was cancelled")
progress = status.get("progress", 0)
print(f"Progress: {progress}%")
time.sleep(interval)
raise TimeoutError("Job polling timed out")
def run(self, endpoint, data, callback=None):
"""Submit and poll until completion."""
job_id = self.submit_job(endpoint, data)
print(f"Job started: {job_id}")
result = self.poll_job(job_id)
if callback:
callback(result)
return result
# Usage
handler = AsyncJobHandler("sk_your_api_key")
result = handler.run(
"videos/generations",
{"prompt": "A sunset over mountains", "duration_seconds": 5}
)
print(f"Video URL: {result['outputData']['video']['url']}")Progress Tracking
async function generateWithProgress(
endpoint: string,
data: object,
onProgress?: (progress: number) => void
): Promise<any> {
// Submit job
const submitResponse = await fetch(
`${BASE_URL}/${endpoint}?async=true`,
{
method: "POST",
headers,
body: JSON.stringify(data),
}
);
const { id: jobId } = await submitResponse.json();
// Poll with progress callback
while (true) {
const statusResponse = await fetch(
`${BASE_URL}/jobs/${jobId}?poll=true`,
{ headers }
);
const status = await statusResponse.json();
if (onProgress && status.progress !== undefined) {
onProgress(status.progress);
}
if (status.status === "completed") {
return status;
}
if (status.status === "failed") {
throw new Error(status.errorMessage);
}
await new Promise((r) => setTimeout(r, 5000));
}
}
// Usage with progress bar
await generateWithProgress(
"videos/generations",
{ prompt: "A flying bird" },
(progress) => console.log(`Progress: ${progress}%`)
);Cancelling Jobs
def cancel_job(job_id):
response = requests.delete(
f"{BASE_URL}/jobs/{job_id}",
headers=headers
)
return response.json().get("success", False)Best Practices
- Implement exponential backoff - Increase poll interval over time
- Set reasonable timeouts - Video: 5 min, Music: 3 min
- Handle all status types - pending, processing, completed, failed, cancelled
- Store job IDs - Allow users to check status later
- Show progress - Use the
progressfield to update UI