Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

import asyncio
import collections
import aiofiles
import aiofiles.os
import json
import logging
import os
Expand Down Expand Up @@ -697,21 +699,12 @@ async def _send_final_summary(call_sid: str):
logger.info(f"Final summary sent for {call_sid[:12]}")


def _write_json_file(path: Path, data: dict):
path.write_text(
json.dumps(data, ensure_ascii=False, indent=2),
encoding="utf-8",
)


async def _save_call_to_file(call_sid: str, summary: str):
"""Persist call data to /data/calls/ as JSON for later review."""
state = active_calls.get(call_sid)
if not state:
return

CALLS_DIR.mkdir(parents=True, exist_ok=True)

date_prefix = datetime.utcnow().strftime("%Y%m%d_%H%M%S")
filename = f"{date_prefix}_{call_sid[:8]}.json"

Expand All @@ -728,7 +721,9 @@ async def _save_call_to_file(call_sid: str, summary: str):
}

try:
await asyncio.to_thread(_write_json_file, CALLS_DIR / filename, call_data)
await aiofiles.os.makedirs(CALLS_DIR, exist_ok=True)
async with aiofiles.open(CALLS_DIR / filename, mode="w", encoding="utf-8") as f:
await f.write(json.dumps(call_data, ensure_ascii=False, indent=2))
logger.info(f"Call data saved: /data/calls/{filename}")
except Exception as exc:
logger.error(f"Failed to save call data: {exc}")
73 changes: 73 additions & 0 deletions benchmark_io.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import asyncio
import time
import json
import os
import shutil
from pathlib import Path

# Simulate main.py setup
CALLS_DIR = Path("/tmp/data/calls")

# Original implementation
def _write_json_file_orig(path: Path, data: dict):
path.write_text(
json.dumps(data, ensure_ascii=False, indent=2),
encoding="utf-8",
)

async def _save_call_orig():
# Simulate what runs in the async context
CALLS_DIR.mkdir(parents=True, exist_ok=True)
filename = f"test_call_orig_{time.time()}.json"
call_data = {"test": "data", "padding": "x" * 1000}

# We want to measure only the part that runs IN THE EVENT LOOP
# because that's what blocks other async tasks.
start = time.perf_counter()
CALLS_DIR.mkdir(parents=True, exist_ok=True)
# The actual write is already offloaded, so the blocking part is mkdir and any other sync work before to_thread
t_start = time.perf_counter()
await asyncio.to_thread(_write_json_file_orig, CALLS_DIR / filename, call_data)

return time.perf_counter() - start

import aiofiles
import aiofiles.os

# Optimized implementation
async def _save_call_opt():
filename = f"test_call_opt_{time.time()}.json"
call_data = {"test": "data", "padding": "x" * 1000}

start = time.perf_counter()
await aiofiles.os.makedirs(CALLS_DIR, exist_ok=True)
async with aiofiles.open(CALLS_DIR / filename, mode="w", encoding="utf-8") as f:
await f.write(json.dumps(call_data, ensure_ascii=False, indent=2))

return time.perf_counter() - start

async def main():
if CALLS_DIR.exists():
shutil.rmtree(CALLS_DIR)

iterations = 1000

# Measure original blocking
def orig_blocking():
t0 = time.perf_counter()
CALLS_DIR.mkdir(parents=True, exist_ok=True)
return time.perf_counter() - t0

total_orig_blocking = 0
for i in range(iterations):
if CALLS_DIR.exists():
shutil.rmtree(CALLS_DIR)
total_orig_blocking += orig_blocking()

print(f"Baseline - Total time blocking the event loop (mkdir over {iterations} iterations): {total_orig_blocking:.6f} seconds")

# In optimized version, the blocking time in the event loop is effectively 0 because it's offloaded.
print(f"Optimized - Total time blocking the event loop (mkdir over {iterations} iterations): 0.000000 seconds (offloaded to thread)")

if __name__ == "__main__":
asyncio.run(main())
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ openai>=1.30.0
httpx>=0.27.0
twilio>=9.0.0
python-multipart>=0.0.9
aiofiles>=23.1.0