CloudTasksQueue.enqueue_batch (src/youtube_extension/services/cloud/cloud_tasks_queue.py) submits tasks in a serial for-loop, awaiting a full Cloud Tasks gRPC round-trip before starting the next. Batch latency is therefore N x RTT.
Production caller: cloud_video_processor.py:288 (task_ids = await tasks_service.enqueue_batch(video_tasks)) - a user-facing batch submission path, so every additional video adds a full RTT to the response.
Measured against the current implementation with a 20ms simulated RTT:
| RTT |
N |
latency |
| 20ms |
10 |
266.5 ms |
| 20ms |
50 |
1338.3 ms |
| 50ms |
50 |
2864.3 ms |
Peak in-flight requests is 1 regardless of batch size, while the queue is provisioned for max_concurrent_dispatches=50 / max_dispatches_per_second=100 - the client is the bottleneck, not the service.
Fix: bounded-concurrent fan-out via asyncio.gather + Semaphore, preserving input-order results and per-task error isolation.
CloudTasksQueue.enqueue_batch (src/youtube_extension/services/cloud/cloud_tasks_queue.py) submits tasks in a serial for-loop, awaiting a full Cloud Tasks gRPC round-trip before starting the next. Batch latency is therefore N x RTT.
Production caller: cloud_video_processor.py:288 (
task_ids = await tasks_service.enqueue_batch(video_tasks)) - a user-facing batch submission path, so every additional video adds a full RTT to the response.Measured against the current implementation with a 20ms simulated RTT:
Peak in-flight requests is 1 regardless of batch size, while the queue is provisioned for max_concurrent_dispatches=50 / max_dispatches_per_second=100 - the client is the bottleneck, not the service.
Fix: bounded-concurrent fan-out via asyncio.gather + Semaphore, preserving input-order results and per-task error isolation.