Async operations

Some operations on Stream's API take longer than a single HTTP response can wait for. Hard-deleting channels, deleting users in bulk, exporting users or calls, and similar batch jobs return a task_id immediately and run in the background. To get the result, poll the task status endpoint.

Task statuses

A task moves through the following statuses:

  • pending: the task is queued and not running yet
  • running: the task is running and not completed yet
  • completed: the task finished successfully
  • failed: the task failed during its execution

The task status response carries the current status, a result payload whose shape depends on the task, and an error with failure details when the task failed.

Waiting on a task

The unified SDKs ship a helper that polls for you and surfaces the outcome as either a typed result (when the task completes) or a typed exception (when it fails or the wait elapses).

from getstream.exceptions import StreamTaskException, StreamTransportException

response = client.delete_channels(cids=["messaging:c1", "messaging:c2"], hard_delete=True)
task_id = response.task_id

try:
    result = client.wait_for_task(task_id)
    print("task completed:", result)
except StreamTaskException as e:
    print(f"task {e.task_id} failed: {e.description}")
except StreamTransportException as e:
    if e.error_type == "timeout":
        # wait elapsed; task may still be running on the server
        ...

The task and transport exceptions are part of the SDK exception hierarchy documented in Error handling.

Behavior

Task outcomeHelper's reaction
status: "completed"Returns the task result payload.
status: "failed"Raises the SDK's task exception with task_id, error_type, description, stack_trace, version.
Deadline exceededRaises the SDK's transport exception with error_type = "timeout". The task may still be running on the server.

Java exposes the server-side stack trace via getStackTraceText(), not getStackTrace(). The latter is reserved for the JVM's own Throwable.getStackTrace() (StackTraceElement[]).

Defaults

ParameterDefault
Poll interval1 second
Wait timeout60 seconds

Override either knob if your task is expected to run longer, or if you want a tighter loop.

client.wait_for_task(task_id, poll_interval=5.0, timeout=600.0)

The async variant in your SDK (for example Python's AsyncStream.wait_for_task or .NET's WaitForTaskAsync) is non-blocking and accepts the same parameters.

Polling manually

If you need a custom polling loop (back-off, progress logging, external cancellation), call getTask yourself. The helper is a convenience over the same endpoint.

const response = await client.exportUsers({
  user_ids: ["<user id1>", "<user id2>"],
});

// poll this endpoint until the status is completed or failed
const taskResponse = await client.getTask({ id: response.task_id });

console.log(taskResponse.status === "completed");