Phase 1: in-memory ConnectionManager viewport fan-out, 500ms map debounce, cachetools TTLCache, background masscan/ffmpeg, compose memory caps. Phase 2: PostGIS geofences + ST_Intersects alerts, Timescale 1-min CAGGs and timestamp playback, FIRMS/WFIGS x firefighting ADS-B within 20 miles. No Redis/Kafka/Celery.
64 lines
1.7 KiB
Python
64 lines
1.7 KiB
Python
"""masscan/ffmpeg stay off the request path (asyncio.create_task)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
|
|
import bg_jobs
|
|
|
|
|
|
def test_schedule_masscan_pass_returns_without_awaiting_scan(monkeypatch):
|
|
started = {"n": 0}
|
|
|
|
async def slow_pass():
|
|
started["n"] += 1
|
|
await asyncio.sleep(30)
|
|
|
|
monkeypatch.setattr(bg_jobs, "_run_masscan_capped", slow_pass)
|
|
bg_jobs._masscan_task = None
|
|
|
|
async def run():
|
|
launched = bg_jobs.schedule_masscan_pass()
|
|
assert launched is True
|
|
# Must not have blocked for the 30s pass.
|
|
assert bg_jobs._masscan_task is not None
|
|
assert not bg_jobs._masscan_task.done()
|
|
launched2 = bg_jobs.schedule_masscan_pass()
|
|
assert launched2 is False # already running
|
|
bg_jobs._masscan_task.cancel()
|
|
try:
|
|
await bg_jobs._masscan_task
|
|
except (asyncio.CancelledError, Exception):
|
|
pass
|
|
bg_jobs._masscan_task = None
|
|
|
|
asyncio.run(run())
|
|
|
|
|
|
def test_masscan_rate_cap_is_200():
|
|
assert bg_jobs.MASSCAN_PPS_CAP == 200
|
|
|
|
|
|
def test_schedule_ffmpeg_snapshot_is_a_task_not_inline(monkeypatch):
|
|
calls = {"n": 0}
|
|
|
|
async def fake_grab(url, timeout=8.0):
|
|
calls["n"] += 1
|
|
await asyncio.sleep(5)
|
|
return b"\xff\xd8fakejpeg"
|
|
|
|
monkeypatch.setattr(bg_jobs, "_ffmpeg_grab", fake_grab)
|
|
bg_jobs._ffmpeg_tasks.clear()
|
|
bg_jobs._ffmpeg_cache.clear()
|
|
|
|
async def run():
|
|
task = bg_jobs.schedule_ffmpeg_snapshot("rtsp://10.0.0.1/")
|
|
assert isinstance(task, asyncio.Task)
|
|
assert not task.done()
|
|
task.cancel()
|
|
try:
|
|
await task
|
|
except (asyncio.CancelledError, Exception):
|
|
pass
|
|
|
|
asyncio.run(run())
|