Problem
ProjectCodeGenerator performs all of its scaffolding disk I/O with blocking primitives
inside async def bodies. Every one of these calls parks the entire event loop for its
duration — not just the calling request.
| Site |
File |
Blocking calls |
What runs on the loop |
generate_project |
code_generator.py:153 |
tempfile.mkdtemp |
directory creation |
_generate_react_project |
code_generator.py:196-289 |
14 |
2× Path.mkdir, 6× open+write, 1× json.dump |
_generate_vanilla_js_project |
code_generator.py:292-343 |
8 |
4× open+write |
_generate_python_api |
code_generator.py:356-390 |
6 |
3× open+write |
Measured payload is small: 6 files / 5,793 B (React), 4 files / 6,888 B (vanilla),
3 files / 2,776 B (FastAPI). On a warm local SSD the whole sequence completes in
sub-millisecond time.
No throughput improvement is claimed. The defect is tail latency and blast radius:
Reachability evidence
Verified at call level, not merely import level:
POST /api/v1/video-to-software router.py:778 (@router.post, mounted in main.py)
-> VideoProcessingService.process_video_to_software video_processing_service.py:317
-> code_generator.generate_project video_processing_service.py:380
-> tempfile.mkdtemp code_generator.py:153
-> _generate_web_project code_generator.py:184
-> _generate_react_project code_generator.py:188
-> _generate_vanilla_js_project code_generator.py:192
-> _generate_api_project -> _generate_python_api code_generator.py:350,354
This is the same HTTP entrypoint whose reachability was independently verified and
merged in #1240, so the chain above is already established in this repository.
Acceptance criteria
Proposed fix
Keep content generation where it is — it is pure in-memory string building and is not
the problem. Collect the resulting (path, content) pairs into a plan, then perform the
whole batch inside a single asyncio.to_thread(...) hop per generator.
One hop per generator rather than one per file keeps the thread-pool cost at O(1) per
request instead of O(files), and preserves write ordering exactly because the batch is
applied sequentially inside the worker.
Problem
ProjectCodeGeneratorperforms all of its scaffolding disk I/O with blocking primitivesinside
async defbodies. Every one of these calls parks the entire event loop for itsduration — not just the calling request.
generate_projectcode_generator.py:153tempfile.mkdtemp_generate_react_projectcode_generator.py:196-289Path.mkdir, 6×open+write, 1×json.dump_generate_vanilla_js_projectcode_generator.py:292-343open+write_generate_python_apicode_generator.py:356-390open+writeMeasured payload is small: 6 files / 5,793 B (React), 4 files / 6,888 B (vanilla),
3 files / 2,776 B (FastAPI). On a warm local SSD the whole sequence completes in
sub-millisecond time.
No throughput improvement is claimed. The defect is tail latency and blast radius:
mkdtempand 13open()calls on acontainer overlayfs, a network mount, or a host under writeback throttling can each
block for tens of milliseconds or longer. Under
vm.dirty_ratiopressure a singlesmall write can stall for seconds.
client alone. Every other coroutine on the same worker — unrelated requests, health
checks, keepalives — is frozen for the same interval.
perf: run npm/tsc verification subprocesses off the event loop #1240 (blocking
subprocess.runindeployment_manager.verify_project).Reachability evidence
Verified at call level, not merely import level:
This is the same HTTP entrypoint whose reachability was independently verified and
merged in #1240, so the chain above is already established in this repository.
Acceptance criteria
generate_project,_generate_react_project,_generate_vanilla_js_project,or
_generate_python_api.layout, same return dictionaries.
exception type to the same caller.
timing.
ruffdiagnostics unchanged versusmainfor every touched file.Proposed fix
Keep content generation where it is — it is pure in-memory string building and is not
the problem. Collect the resulting
(path, content)pairs into a plan, then perform thewhole batch inside a single
asyncio.to_thread(...)hop per generator.One hop per generator rather than one per file keeps the thread-pool cost at O(1) per
request instead of O(files), and preserves write ordering exactly because the batch is
applied sequentially inside the worker.