Measure time to usable media from the moment your application starts an ingestion task to the moment its intended consumer can actually use the output. Keep that measure separate from API response time and server-side processing duration. A fast acknowledgement does not mean a file is ready.
The definition of “usable” belongs to your application. It might mean a downloaded file passes validation, or that a downstream service accepts the media as input. Choose one boundary and name it precisely before comparing results.
Record milestones that explain the wait
Use an application item ID to connect the stages and preserve the remote job ID once available. Record each milestone only when it actually occurs:
| Milestone | Meaning |
|---|---|
| Task started | Your application begins the ingestion attempt |
| Job acknowledged | The API returns a known job identifier |
| Completion observed | Your application learns the media job completed |
| File accessible | Your consumer successfully accesses the output |
| Media usable | Your chosen validation or acceptance condition passes |
The intervals between milestones help locate delays. Completion observation includes notification or polling delay, so it is not identical to the provider's internal finish time. Likewise, retrieving a signed link does not establish that the consumer has read the file.
In Tornado API's asynchronous workflow, preserve the job ID and follow the result before consuming delivery access. The Python job tutorial demonstrates that sequence and a finite client waiting budget.
Keep clocks and boundaries consistent
For an elapsed interval measured inside one running process, use a monotonic clock. Python documents time.monotonic as a clock unaffected by system-clock updates; only differences between its readings are meaningful.
Do not subtract arbitrary monotonic readings from different machines or store one expecting it to retain the same reference across deployments. For distributed or restartable workflows, preserve timestamps and clock context, account for synchronization uncertainty, and use tracing or other instrumentation designed for cross-service analysis.
A negative duration should trigger investigation, not be silently converted to zero. Record which system produced a timestamp and whether an interval measures processing, transport, or observation.
Show failures alongside successful timings
An unsuccessful task never reaches the chosen usable boundary. Report its outcome and time to failure separately. A task still running at the end of your observation window also has no completed usability duration yet.
Do not replace those missing durations with zero, and do not label the median of successful tasks as the experience of every submitted task. A system can appear faster when its slowest work simply stops succeeding.
Google's SRE monitoring guidance discusses latency distributions and percentiles as a way to expose variation hidden by averages. Use these statistics with the sample count, outcome counts, and measurement window attached. A tiny sample does not establish a stable tail-latency estimate.
Calculate a transparent sample report
This Python example uses invented observations, not Tornado performance measurements. It reports successful timing together with unfinished and failed tasks:
from statistics import median
# Synthetic observations: seconds elapsed since each item's start.
rows = [
{"outcome": "usable", "elapsed": 8.0},
{"outcome": "usable", "elapsed": 12.0},
{"outcome": "usable", "elapsed": 25.0},
{"outcome": "failed", "elapsed": 6.0},
{"outcome": "pending", "elapsed": 30.0},
]
successes = [r["elapsed"] for r in rows if r["outcome"] == "usable"]
report = {
"started": len(rows),
"usable": len(successes),
"failed": sum(r["outcome"] == "failed" for r in rows),
"pending": sum(r["outcome"] == "pending" for r in rows),
"successful_median_seconds": median(successes) if successes else None,
}
assert report == {
"started": 5, "usable": 3, "failed": 1, "pending": 1,
"successful_median_seconds": 12.0,
}
print(report)
The code and assertion were executed locally. The result is three usable items, one failure, one pending item, and a 12-second median among the three successes. It is an arithmetic check, not a benchmark or processing-time promise.
The pending item's elapsed value describes its age at observation, not its eventual completion time. Keep the reporting window explicit and update the cohort when a later outcome arrives. In a production report, also handle cancellation and unknown submission outcomes rather than forcing them into success or failure.
Compare like workloads
Segment observations by factors that change the work: source category, duration range, requested output, destination, and relevant consumer configuration. Preserve the configuration version when you change the pipeline.
A comparison between short audio extracts and long video deliveries is not evidence that one implementation is faster. Use representative inputs and the same usability definition for both configurations. Separate cold-start or first-use observations when they differ meaningfully from steady operation.
Track retries as well. An item that succeeds after multiple attempts has both attempt-level timings and an overall elapsed time from the original task start. Resetting the main timer on every retry hides part of the user's wait.
Turn timing into a recovery decision
When the wait exceeds your application's budget, record a timeout observation without assuming the remote job was cancelled. If its ID is known, reconcile that same job. If media already exists but the consumer cannot read it, investigate access and format rather than automatically submitting another download.
For groups of items, keep individual outcomes visible. The partial-batch recovery guide explains how to resume a failing stage while retaining successful work.
Use the milestone breakdown to choose what to improve next. A long gap before job acknowledgement points to a different part of the system than a long gap between completion observation and consumer acceptance. Validate the cause with records before attributing every delay to media processing.
Start with one instrumented path
Choose one authorized source and one consumer, write down the exact usable boundary, and record the milestones through that path. Check interruption and failure cases as well as success. Keep job IDs and destination references in operational records, while excluding API keys and signed access links from general analytics.
Use the first-workflow guide to establish a working ingestion path. Then collect representative observations before choosing a latency target. Your own measured distribution and recovery needs should drive that target; this article supplies no universal SLA.