mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-08-05 02:45:28 +00:00
Merge 10847bbb0f into fb8c391a88
This commit is contained in:
commit
5c96e26d43
3 changed files with 63 additions and 7 deletions
15
app.py
15
app.py
|
|
@ -630,14 +630,15 @@ app.include_router(auth_router)
|
||||||
|
|
||||||
@app.post("/api/activity/heartbeat")
|
@app.post("/api/activity/heartbeat")
|
||||||
async def activity_heartbeat():
|
async def activity_heartbeat():
|
||||||
from src.interactive_gate import mark_browser_activity
|
from src.interactive_gate import mark_browser_activity, _enabled as _gate_enabled
|
||||||
await mark_browser_activity()
|
await mark_browser_activity()
|
||||||
async def _stop_background():
|
if _gate_enabled():
|
||||||
try:
|
async def _stop_background():
|
||||||
await task_scheduler.stop_background_tasks_for_foreground(reason="browser heartbeat")
|
try:
|
||||||
except Exception:
|
await task_scheduler.stop_background_tasks_for_foreground(reason="browser heartbeat")
|
||||||
logging.getLogger("app.foreground_gate").debug("heartbeat task stop failed", exc_info=True)
|
except Exception:
|
||||||
asyncio.create_task(_stop_background())
|
logging.getLogger("app.foreground_gate").debug("heartbeat task stop failed", exc_info=True)
|
||||||
|
asyncio.create_task(_stop_background())
|
||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ _PASSIVE_EXACT_PATHS = {
|
||||||
"/api/activity/heartbeat",
|
"/api/activity/heartbeat",
|
||||||
"/api/client-perf",
|
"/api/client-perf",
|
||||||
"/api/tasks/notifications",
|
"/api/tasks/notifications",
|
||||||
|
"/api/tasks/runs/recent",
|
||||||
"/api/research/active",
|
"/api/research/active",
|
||||||
"/api/email/urgency-state",
|
"/api/email/urgency-state",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
54
tests/test_poll_endpoint_no_task_interrupt.py
Normal file
54
tests/test_poll_endpoint_no_task_interrupt.py
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
"""Regression: read-only task-status polling must not interrupt running background tasks.
|
||||||
|
|
||||||
|
GET /api/tasks/runs/recent is called by the Activity view while a scheduled
|
||||||
|
task is executing. Before this fix, the _InteractiveActivityMiddleware treated
|
||||||
|
it as a foreground request and called stop_background_tasks_for_foreground,
|
||||||
|
which immediately cancelled the running task. The fix adds the endpoint to
|
||||||
|
_PASSIVE_EXACT_PATHS so it is excluded from interactive tracking.
|
||||||
|
|
||||||
|
Additionally, /api/activity/heartbeat called stop_background_tasks_for_foreground
|
||||||
|
unconditionally, ignoring BACKGROUND_TASK_FOREGROUND_GATE=false. The fix wraps
|
||||||
|
that call in a _gate_enabled() check so the env var fully disables interrupts.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import importlib
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def _reload_gate():
|
||||||
|
import src.interactive_gate as ig
|
||||||
|
importlib.reload(ig)
|
||||||
|
return ig
|
||||||
|
|
||||||
|
|
||||||
|
def test_tasks_runs_recent_is_passive():
|
||||||
|
ig = _reload_gate()
|
||||||
|
assert not ig.should_track_interactive_request("/api/tasks/runs/recent", "GET"), (
|
||||||
|
"GET /api/tasks/runs/recent must be treated as a passive endpoint so that "
|
||||||
|
"the Activity-view polling does not trigger stop_background_tasks_for_foreground "
|
||||||
|
"and cancel running scheduled tasks"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_tasks_runs_recent_does_not_affect_other_task_paths():
|
||||||
|
ig = _reload_gate()
|
||||||
|
# Non-polling mutating task routes should still be interactive.
|
||||||
|
assert ig.should_track_interactive_request("/api/tasks/runs/recent/something", "POST")
|
||||||
|
|
||||||
|
|
||||||
|
def test_heartbeat_respects_foreground_gate_disabled(monkeypatch):
|
||||||
|
"""stop_background_tasks_for_foreground must NOT be called from the heartbeat
|
||||||
|
handler when BACKGROUND_TASK_FOREGROUND_GATE=false."""
|
||||||
|
monkeypatch.setenv("BACKGROUND_TASK_FOREGROUND_GATE", "false")
|
||||||
|
ig = _reload_gate()
|
||||||
|
assert not ig._enabled(), (
|
||||||
|
"_enabled() should return False when BACKGROUND_TASK_FOREGROUND_GATE=false"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_heartbeat_gate_enabled_by_default(monkeypatch):
|
||||||
|
monkeypatch.delenv("BACKGROUND_TASK_FOREGROUND_GATE", raising=False)
|
||||||
|
ig = _reload_gate()
|
||||||
|
assert ig._enabled(), (
|
||||||
|
"_enabled() should return True by default (foreground gate on)"
|
||||||
|
)
|
||||||
Loading…
Add table
Reference in a new issue