perf: move blocking homepage and hash I/O off loop
Quality Gate / gate (push) Failing after 47s

Co-authored-by: Copilot App <[email protected]>
This commit is contained in:
Jim Lancaster
2026-08-23 18:41:01 -05:00
co-authored by Copilot App
parent 2093eb6fb3
commit 3873810022
9 changed files with 43 additions and 12 deletions
+1
View File
@@ -60,6 +60,7 @@ WORKER_PROVIDER_TIMEOUT_SECONDS=30.0
WORKER_STALE_JOB_SECONDS=30.0
WORKER_RETRY_BACKOFF_SECONDS=1.0
WORKER_SHUTDOWN_GRACE_SECONDS=5.0
WORKER_POLL_INTERVAL_SECONDS=1.0
WORKER_MIN_TRANSCRIPTION_CHARS=0
WORKER_MIN_TRANSCRIPTION_LINES=0
WORKER_FAIL_ON_FINISH_REASON_LENGTH=false
+1 -1
View File
@@ -59,7 +59,7 @@ async def _lifespan(app: FastAPI):
stop_event, worker_notifier, worker_health = await stack.enter_async_context(
worker_consumer_lifespan(
session_factory=app.state.runtime.session_factory,
poll_interval_seconds=1.0,
poll_interval_seconds=settings.worker_poll_interval_seconds,
shutdown_timeout_seconds=(
settings.worker_provider_timeout_seconds + settings.worker_shutdown_grace_seconds
),
+1
View File
@@ -117,6 +117,7 @@ class Settings(BaseSettings):
worker_stale_job_seconds: float = Field(default=30.0, gt=0.0)
worker_retry_backoff_seconds: float = Field(default=1.0, ge=0.0)
worker_shutdown_grace_seconds: float = Field(default=5.0, ge=0.0)
worker_poll_interval_seconds: float = Field(default=1.0, gt=0.0)
worker_min_transcription_chars: int = Field(default=0, ge=0)
worker_min_transcription_lines: int = Field(default=0, ge=0)
worker_fail_on_finish_reason_length: bool = False
+6 -1
View File
@@ -1,5 +1,6 @@
from __future__ import annotations
import asyncio
import hashlib
import logging
from collections.abc import Sequence
@@ -398,6 +399,10 @@ async def store_source_file(
)
return StoredSourceFile(
path=stored_path,
file_hash=hashlib.sha256(file_bytes).hexdigest(),
file_hash=await asyncio.to_thread(_sha256_hexdigest, file_bytes),
file_size_bytes=len(file_bytes),
)
def _sha256_hexdigest(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()
+24 -5
View File
@@ -2,6 +2,7 @@
from __future__ import annotations
import asyncio
from collections.abc import Callable
from fastapi import Request
@@ -116,7 +117,7 @@ def _render_homepage_view(*, markdown_text: str, render_image_panel: Callable[[]
ui.element("div")
def _render_homepage_editor(*, render_image_panel, markdown_input, on_upload) -> None:
def _render_homepage_editor(*, render_image_panel, markdown_input, on_upload, initial_markdown: str) -> None:
with ui.grid().classes("w-full grid-cols-12 gap-4"):
with ui.column().classes("col-span-12 lg:col-span-4 gap-4"):
with archival_card(title="Homepage Image"):
@@ -132,7 +133,7 @@ def _render_homepage_editor(*, render_image_panel, markdown_input, on_upload) ->
markdown_input[0] = (
ui.textarea(
label="Homepage markdown",
value=read_homepage_markdown(),
value=initial_markdown,
)
.props("outlined autogrow")
.classes("w-full")
@@ -152,6 +153,7 @@ def register_page() -> None: # noqa: PLR0915
render_navigation_header(current_path="/homepage")
photos = await photos_service.list_photos(person_id=None)
active_index = [0]
homepage_markdown = [""]
@ui.refreshable
def render_image_panel() -> None:
@@ -172,12 +174,20 @@ def register_page() -> None: # noqa: PLR0915
on_click=lambda: ui.navigate.to("/homepage/edit"),
icon="edit",
).classes("ui-btn-primary text-xs")
@ui.refreshable
def render_home_content() -> None:
_render_homepage_view(
markdown_text=read_homepage_markdown().strip(),
markdown_text=homepage_markdown[0].strip(),
render_image_panel=render_image_panel,
)
@ui.page("/homepage/edit", title="Edit Homepage")
render_home_content()
homepage_markdown[0] = await asyncio.to_thread(read_homepage_markdown, settings)
render_home_content.refresh()
@ui.page("/homepage/edit", title="Edit Home Page")
async def homepage_edit_page(request: Request, session_factory: SessionFactoryDep) -> None: # noqa: PLR0915
photos_service = PhotosService(session_factory=session_factory)
settings = resolve_runtime_settings(request)
@@ -268,7 +278,11 @@ def register_page() -> None: # noqa: PLR0915
ui.navigate.to("/homepage/edit")
async def save_homepage() -> None:
save_homepage_markdown((markdown_input[0].value if markdown_input[0] is not None else "") or "")
await asyncio.to_thread(
save_homepage_markdown,
(markdown_input[0].value if markdown_input[0] is not None else "") or "",
settings,
)
ui.notify("Homepage saved", type="positive")
ui.navigate.to("/homepage")
@@ -283,4 +297,9 @@ def register_page() -> None: # noqa: PLR0915
render_image_panel=render_image_panel,
markdown_input=markdown_input,
on_upload=on_upload,
initial_markdown="",
)
loaded_markdown = await asyncio.to_thread(read_homepage_markdown, settings)
if markdown_input[0] is not None:
markdown_input[0].value = loaded_markdown
+3 -2
View File
@@ -2,6 +2,7 @@
from __future__ import annotations
import asyncio
from typing import Any
from uuid import UUID
@@ -540,8 +541,8 @@ async def _recover_prompt(prompts: PromptStore, name: str) -> None:
async def _read_home_page_text(settings: Settings) -> str:
return read_homepage_markdown(settings=settings)
return await asyncio.to_thread(read_homepage_markdown, settings=settings)
async def _write_home_page_text(settings: Settings, markdown_text: str) -> None:
save_homepage_markdown(markdown_text, settings=settings)
await asyncio.to_thread(save_homepage_markdown, markdown_text, settings=settings)
+2
View File
@@ -65,6 +65,7 @@ class TestAppLifespan:
openrouter_api_key="test-key",
environment="test",
bootstrap_schema_on_startup=True,
worker_poll_interval_seconds=2.5,
upload_dir=tmp_path / "uploads",
prompt_dir=tmp_path / "prompts",
)
@@ -80,6 +81,7 @@ class TestAppLifespan:
assert "worker_start" in calls
assert "worker_stop" in calls
assert "dispose_db" in calls
assert worker_kwargs["poll_interval_seconds"] == pytest.approx(settings.worker_poll_interval_seconds)
assert worker_kwargs["shutdown_timeout_seconds"] == pytest.approx(
settings.worker_provider_timeout_seconds + settings.worker_shutdown_grace_seconds
)
+1
View File
@@ -170,6 +170,7 @@ class TestWorkerReliabilitySettings:
assert settings.worker_stale_job_seconds == 30.0
assert settings.worker_retry_backoff_seconds == 1.0
assert settings.worker_shutdown_grace_seconds == 5.0
assert settings.worker_poll_interval_seconds == 1.0
def test_provider_timeout_is_not_capped_at_twenty_seconds():
+1
View File
@@ -170,6 +170,7 @@ def test_env_example_default_values_match_settings_defaults():
"WORKER_STALE_JOB_SECONDS": str(defaults.worker_stale_job_seconds),
"WORKER_RETRY_BACKOFF_SECONDS": str(defaults.worker_retry_backoff_seconds),
"WORKER_SHUTDOWN_GRACE_SECONDS": str(defaults.worker_shutdown_grace_seconds),
"WORKER_POLL_INTERVAL_SECONDS": str(defaults.worker_poll_interval_seconds),
"WORKER_MIN_TRANSCRIPTION_CHARS": str(defaults.worker_min_transcription_chars),
"WORKER_MIN_TRANSCRIPTION_LINES": str(defaults.worker_min_transcription_lines),
"WORKER_FAIL_ON_FINISH_REASON_LENGTH": str(defaults.worker_fail_on_finish_reason_length).lower(),