Skip to main content
Run and Scale

Async task management

Two async patterns on Qwen Cloud: task-based for media generation, batch for high-volume text processing

Qwen Cloud offers two async processing systems. Choose based on what you're building:
Task APIBatch API
Use caseImage generation, video generation, file transcriptionHigh-volume text generation, embeddings
How it worksSubmit one request → get a task ID → poll for resultUpload a JSONL file of requests → poll for completion → download results
Endpointdashscope-intl.aliyuncs.com/api/v1/tasks/dashscope-intl.aliyuncs.com/compatible-mode/v1/batches
CostStandard pricing50% discount
Completion timeSeconds to minutesUp to 24h (configurable to 336h)
Result retention24 hours30 days
Max per request1 task (with optional multi-output like n=4)50,000 requests per file, 500 MB

Task API

Image generation, video generation, and file transcription use the Task API: you submit a single request, receive a task ID, and poll for the result.

How it works

Every task follows the same two-step pattern:
  1. Create a task — Send a POST request and receive a task_id
  2. Query the result — Poll GET /api/v1/tasks/{task_id} until the task reaches a terminal state
POST (create) ──→ task_id

       ┌─────────────┘

  ┌─────────┐    ┌─────────┐    ┌───────────┐
  │ PENDING │───→│ RUNNING │───→│ SUCCEEDED │
  └─────────┘    └─────────┘    └───────────┘
       │              │
       ▼              ▼
  ┌──────────┐   ┌────────┐
  │ CANCELED │   │ FAILED │
  └──────────┘   └────────┘

Task states

StateMeaning
PENDINGQueued, waiting to start
RUNNINGActively processing
SUCCEEDEDCompleted successfully
FAILEDEncountered an error
CANCELEDManually canceled (only from PENDING state)
UNKNOWNTask ID expired or cannot be queried

Create a task

Some APIs (like image generation) support both synchronous and asynchronous modes. Add the X-DashScope-Async header to force async execution:
curl -X POST https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/image-generation/generation \
  -H "Authorization: Bearer $DASHSCOPE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-DashScope-Async: enable" \
  -d '{
    "model": "wan2.6-t2i",
    "input": {
      "prompt": "A cat sitting on a windowsill at sunset"
    }
  }'
The response returns a task_id:
{
  "request_id": "e5d5af82-9a08-xxx",
  "output": {
    "task_id": "86ecf553-d340-xxx",
    "task_status": "PENDING"
  }
}
Video generation APIs are always asynchronous — you do not need the X-DashScope-Async header for these.

Query the result

Poll the task endpoint with the returned task_id:
  • curl
  • Python
curl -X GET "https://dashscope-intl.aliyuncs.com/api/v1/tasks/86ecf553-d340-xxx" \
  -H "Authorization: Bearer $DASHSCOPE_API_KEY"
A completed task returns the result in the output field:
{
  "request_id": "e5d5af82-9a08-xxx",
  "output": {
    "task_id": "86ecf553-d340-xxx",
    "task_status": "SUCCEEDED",
    "submit_time": "2025-01-15 10:30:00.000",
    "scheduled_time": "2025-01-15 10:30:01.000",
    "end_time": "2025-01-15 10:30:12.000",
    "results": [
      {
        "url": "https://dashscope-result-xxx.oss-xxx.aliyuncs.com/..."
      }
    ],
    "task_metrics": {
      "TOTAL": 1,
      "SUCCEEDED": 1,
      "FAILED": 0
    }
  },
  "usage": {
    "image_count": 1
  }
}
A failed task includes an error code and message:
{
  "output": {
    "task_id": "86ecf553-d340-xxx",
    "task_status": "FAILED",
    "code": "DataInspectionFailed",
    "message": "Input or output data may contain inappropriate content."
  }
}

Polling strategies

Naive fixed-interval polling wastes API calls and may hit rate limits. Use exponential backoff instead. Start with a short interval and increase gradually. Different modalities have different typical completion times:
ModalityInitial intervalIncrease factorTimeout
Image generation3 seconds1.5×2 minutes
Video generation15 seconds1.5×5 minutes
File transcription (ASR)5 seconds1.5×Varies with audio length
  • Python
  • Node.js
import time
import requests
import os

def poll_task(task_id, initial_interval=3, max_interval=15, timeout=120):
  """Poll a task with exponential backoff."""
  url = f"https://dashscope-intl.aliyuncs.com/api/v1/tasks/{task_id}"
  headers = {"Authorization": f"Bearer {os.getenv('DASHSCOPE_API_KEY')}"}

  interval = initial_interval
  elapsed = 0

  while elapsed < timeout:
    response = requests.get(url, headers=headers)
    result = response.json()
    status = result["output"]["task_status"]

    if status == "SUCCEEDED":
      return result
    elif status == "FAILED":
      raise Exception(
        f"Task failed: {result['output'].get('code', 'Unknown')} - "
        f"{result['output'].get('message', '')}"
      )

    time.sleep(interval)
    elapsed += interval
    interval = min(interval * 1.5, max_interval)

  raise TimeoutError(f"Task {task_id} did not complete within {timeout}s")

# Image generation: poll every 3s, escalate to 15s, timeout at 2min
result = poll_task("86ecf553-d340-xxx", initial_interval=3, max_interval=15, timeout=120)

# Video generation: poll every 15s, escalate to 60s, timeout at 5min
result = poll_task("86ecf553-d340-xxx", initial_interval=15, max_interval=60, timeout=300)

SDK-level abstraction

The DashScope Python SDK encapsulates the polling loop. Use call() for a synchronous experience, or async_call() + wait() for explicit control:
from dashscope import ImageSynthesis

# Option 1: Synchronous — SDK polls internally
result = ImageSynthesis.call(
  model="wan2.6-t2i",
  prompt="A cat sitting on a windowsill at sunset",
  n=1
)
print(result.output.results[0].url)

# Option 2: Explicit async — you control when to wait
task = ImageSynthesis.async_call(
  model="wan2.6-t2i",
  prompt="A cat sitting on a windowsill at sunset",
  n=1
)
# Do other work here...
result = ImageSynthesis.wait(task)
print(result.output.results[0].url)
The same pattern applies across modalities:
from dashscope import VideoSynthesis

task = VideoSynthesis.async_call(model="wan2.1-t2v-plus", prompt="...")
result = VideoSynthesis.wait(task)

Manage tasks at scale

List tasks

Query tasks by time range, status, or model:
curl -X GET "https://dashscope-intl.aliyuncs.com/api/v1/tasks/?start_time=20250115100000&end_time=20250115120000&status=FAILED&model_name=wan2.6-t2i&page_no=1&page_size=20" \
  -H "Authorization: Bearer $DASHSCOPE_API_KEY"
Supported filters:
ParameterDescription
start_timeStart of time range, format: YYYYMMDDhhmmss
end_timeEnd of time range, format: YYYYMMDDhhmmss
statusFilter by task status (PENDING, RUNNING, SUCCEEDED, FAILED)
model_nameFilter by model name
page_noPage number (starting from 1)
page_sizeResults per page
The time range cannot exceed 24 hours. If both start_time and end_time are omitted, the API returns tasks from the last 24 hours.

Cancel a task

Cancel a task that is still in PENDING state:
curl -X POST "https://dashscope-intl.aliyuncs.com/api/v1/tasks/86ecf553-d340-xxx/cancel" \
  -H "Authorization: Bearer $DASHSCOPE_API_KEY"
Only tasks in PENDING state can be canceled. Once a task moves to RUNNING, it will continue to completion.

Rate limits

Task management endpoints (query, list, cancel) share a rate limit of 20 QPS per account. If you manage many concurrent tasks, batch your status checks rather than polling each task individually at high frequency.

Task API best practices

Download results immediately — Task data and result URLs (images, videos) are retained for 24 hours only. After that, both the task metadata and generated files are automatically deleted. Always download and save results to persistent storage as soon as the task succeeds. Handle multi-output tasks — When you request multiple outputs (such as n=4 images), the task is marked SUCCEEDED if at least one output is generated. Check the task_metrics field and iterate over the results array to handle partial success:
result = poll_task(task_id)
metrics = result["output"]["task_metrics"]
print(f"{metrics['SUCCEEDED']}/{metrics['TOTAL']} outputs generated")

for item in result["output"]["results"]:
  if "url" in item:
    download(item["url"])
  else:
    print(f"Failed: {item.get('message', 'Unknown error')}")
Avoid duplicate tasks — Each POST request creates a new task, even with identical parameters. If your application retries a failed submission, track task IDs to avoid duplicate work and unnecessary cost.

Batch API

The Batch API processes large volumes of text generation or embedding requests at 50% of the standard price. You upload a JSONL file of requests, wait for processing to complete, and download the results.
FeatureDetails
Supported modelsQwen text generation models, text embedding models
Input formatJSONL file, up to 50,000 requests / 500 MB
Completion window24 hours (configurable up to 336 hours)
Result retention30 days
CancellationSupported at any stage (in-progress requests finish first)
The Batch API uses the OpenAI-compatible endpoint and SDK. For the complete guide with examples, input format, task states, and management operations, see Batch API.

Common errors

These errors apply to both the Task API and the Batch API:
ErrorCauseAction
DataInspectionFailedInput or output blocked by content moderationModify the prompt and retry. See Safety
Throttling.RateQuotaRate limit exceededReduce request frequency; increase polling interval
Task/batch stuckProcessing taking longer than expectedFor tasks: continue polling until timeout. For batches: increase completion_window

Next steps