|
| 1 | +import os |
| 2 | +import asyncio |
| 3 | + |
| 4 | + |
| 5 | +async def my_coroutine(n: float) -> None: |
| 6 | + await asyncio.sleep(n) |
| 7 | + |
| 8 | + |
| 9 | +async def main() -> None: |
| 10 | + # Simple application that creates two Tasks with different durations: |
| 11 | + # - "unnamed Task" runs my_coroutine() for 2 second |
| 12 | + # - short_task runs my_coroutine() for 1 second |
| 13 | + # The profiler should capture both Tasks with their respective durations. |
| 14 | + |
| 15 | + # Note: there currently is an issue in ddtrace that attaches one of the gathered Tasks to the "parent" |
| 16 | + # task. As a result, using an explicit name for the manually started Task would result in flakiness (as we cannot |
| 17 | + # know which Task name will be "absorbed" by the Parent). |
| 18 | + # For the time being, we thus don't name the Task, so that we will always have Task-1 and Task-2 in the Profile. |
| 19 | + |
| 20 | + # Note: additionally, there is an issue in how we count wall time that results in blatantly incorrect results. |
| 21 | + # We are in the process of making asyncio better in dd-trace-py; we will update the correctness check once that |
| 22 | + # issue is fixed. |
| 23 | + |
| 24 | + from ddtrace.profiling import Profiler |
| 25 | + |
| 26 | + prof = Profiler() |
| 27 | + prof.start() # Should be as early as possible, eg before other imports, to ensure everything is profiled |
| 28 | + |
| 29 | + # Give the Profiler some time to start up |
| 30 | + await asyncio.sleep(0.5) |
| 31 | + |
| 32 | + EXECUTION_TIME_SEC = float(os.environ.get("EXECUTION_TIME_SEC", "2")) |
| 33 | + |
| 34 | + short_task = asyncio.create_task(my_coroutine(EXECUTION_TIME_SEC / 2)) |
| 35 | + |
| 36 | + # asyncio.gather will automatically wrap my_coroutine into a Task |
| 37 | + await asyncio.gather(short_task, my_coroutine(EXECUTION_TIME_SEC)) |
| 38 | + |
| 39 | + |
| 40 | +if __name__ == "__main__": |
| 41 | + asyncio.run(main()) |
0 commit comments