Learn how to build a reliable polling workflow in Serverless Workflow to track the status of a long-running task until it completes.
How the polling pattern works
The polling pattern is a recurring process that periodically checks an external system until a condition is met — for example, querying job status until it succeeds or fails. Unlike a fixed-interval timer trigger, a Serverless Workflow polling loop waits between iterations (avoiding overlap) and persists its state, so the workflow resumes from where it left off if the polling process fails mid-run.
Use this pattern when a long-running task does not support callbacks. If the task can notify your workflow on completion, use a callback instead — it is simpler and more efficient.
This tutorial implements a polling workflow for a multimedia processing task that may take anywhere from one minute to several hours. The workflow periodically calls a status-check function and exits as soon as the task succeeds — or after three polling attempts if it has not.
Implementation in Serverless Workflow
This tutorial walks through the following three steps to build the polling workflow:
Step 1: Create a function in Function Compute
Create a service named fnf-demo in Function Compute, then create the following two Python 3.10 functions in that service. For setup instructions, see Quickly create a function.
-
StartJob — simulates calling an API to start a long-running task. Returns a unique job ID that the polling loop uses to track that task.
import logging import uuid def handler(event, context): logger = logging.getLogger() id = uuid.uuid4() logger.info('Started job with ID %s' % id) return {"job_id": str(id)} -
GetJobStatus — simulates calling an API to check the status of a running task. It compares the elapsed time since first execution against the
delaythreshold and returns either"success"or"running". It also incrementstry_counton each call so the workflow can enforce a maximum retry limit.import logging import uuid import time import json # Record the time this function instance was first loaded start_time = int(time.time()) def handler(event, context): evt = json.loads(event) logger = logging.getLogger() job_id = evt["job_id"] logger.info('Started job with ID %s' % job_id) now = int(time.time()) status = "running" # Default delay before the task is considered complete (seconds) delay = 60 if "delay" in evt: delay = evt["delay"] # If enough time has elapsed, mark the task as successful if now - start_time > delay: status = "success" try_count = 0 if "try_count" in evt: try_count = evt["try_count"] # Track how many times the status has been polled try_count = try_count + 1 logger.info('Job %s, status %s, try_count %d' % (job_id, status, try_count)) return {"job_id": job_id, "job_status":status, "try_count":try_count}
Step 2: Create a workflow in Serverless Workflow
In the Flows page of the CloudFlow console, click Create Flow. In the Flow Definition step of the Create Flow wizard, configure the Details and Definition sections.
The workflow runs the following polling loop:
StartJob: Calls the
StartJobfunction to start the task and get its job ID.Wait10s: Pauses for 10 seconds before the next status check, preventing unnecessary API calls.
GetJobStatus: Calls the
GetJobStatusfunction to query the current task status.-
CheckJobComplete: Evaluates the status returned by
GetJobStatusand branches accordingly:"success"— the workflow ends successfully.try_count > 3— the task has been polled three or more times without completing, so the workflow fails."running"— loops back to theWait10sstep to wait before the next poll.
version: v1 type: flow steps: - type: task name: StartJob resourceArn: acs:fc:{region}:{accountID}:services/fnf-demo/functions/StartJob - type: pass name: Init outputMappings: - target: try_count source: 0 - type: wait name: Wait10s duration: 10 - type: task name: GetJobStatus resourceArn: acs:fc:{region}:{accountID}:services/fnf-demo/functions/GetJobStatus inputMappings: - target: job_id source: $local.job_id - target: delay source: $input.delay - target: try_count source: $local.try_count - type: choice name: CheckJobComplete inputMappings: - target: status source: $local.job_status - target: try_count source: $local.try_count choices: - condition: $.status == "success" goto: JobSucceeded - condition: $.try_count > 3 goto: JobFailed - condition: $.status == "running" goto: Wait10s - type: succeed name: JobSucceeded - type: fail name: JobFailed
Step 3: Execute the workflow and view the result
In the CloudFlow console, find the workflow, click Start Execution, and enter the following JSON as the execution input. The delay value controls how many seconds the task takes to complete. With delay set to 20, the GetJobStatus function returns "running" for the first 20 seconds, then "success". Adjust delay to observe different execution paths.
{
"delay": 20
}
The following figure shows the visual execution trace of the polling workflow from start to finish.

As shown below, the task takes 20 seconds. The first call to
GetJobStatusreturns"running", soCheckJobCompletesends the workflow back toWait10s. The second call returns"success", and the workflow ends successfully.