feat: add TTLCache for get_cache_version and TEMPLATE_AUTO_RELOAD config with Makefile worker count variables

This commit is contained in:
2026-06-14 14:46:36 +00:00
parent c151325916
commit d75d5dc6a8
149 changed files with 9811 additions and 262 deletions
+56 -33
View File
@@ -2,18 +2,30 @@
import asyncio
import logging
import queue
import threading
from typing import Any, Callable, Optional
logger = logging.getLogger(__name__)
QUEUE_MAXSIZE = 10000
DRAIN_BATCH = 64
JOIN_TIMEOUT_SECONDS = 10
GET_TIMEOUT_SECONDS = 1
class _Stop:
pass
_STOP = _Stop()
class BackgroundQueue:
def __init__(self, maxsize: int = QUEUE_MAXSIZE) -> None:
self._queue: asyncio.Queue = asyncio.Queue(maxsize=maxsize)
self._task: Optional[asyncio.Task] = None
self._queue: "queue.Queue" = queue.Queue(maxsize=maxsize)
self._thread: Optional[threading.Thread] = None
self._loop: Optional[asyncio.AbstractEventLoop] = None
self._counters_lock = threading.Lock()
self._submitted = 0
self._processed = 0
self._failed = 0
@@ -21,44 +33,55 @@ class BackgroundQueue:
@property
def running(self) -> bool:
return self._task is not None and not self._task.done()
return self._thread is not None and self._thread.is_alive()
@property
def loop(self) -> Optional[asyncio.AbstractEventLoop]:
return self._loop
def submit(self, fn: Callable[..., Any], *args: Any, **kwargs: Any) -> None:
self._submitted += 1
with self._counters_lock:
self._submitted += 1
if not self.running:
self._execute(fn, args, kwargs, inline=True)
return
try:
self._queue.put_nowait((fn, args, kwargs))
except asyncio.QueueFull:
except queue.Full:
logger.warning("background queue full; running task inline")
self._execute(fn, args, kwargs, inline=True)
def _execute(self, fn: Callable[..., Any], args: tuple, kwargs: dict, inline: bool = False) -> None:
if inline:
self._inline += 1
try:
fn(*args, **kwargs)
self._processed += 1
with self._counters_lock:
self._processed += 1
if inline:
self._inline += 1
except Exception as exc:
self._failed += 1
with self._counters_lock:
self._failed += 1
if inline:
self._inline += 1
logger.warning("background task %s failed: %s", getattr(fn, "__name__", fn), exc)
async def start(self) -> None:
if self.running:
return
self._task = asyncio.create_task(self._drain())
logger.info("background task queue started")
self._loop = asyncio.get_running_loop()
self._thread = threading.Thread(
target=self._worker, name="background-queue", daemon=True
)
self._thread.start()
logger.info("background task queue worker thread started")
async def stop(self) -> None:
task = self._task
self._task = None
if task is not None:
task.cancel()
try:
await task
except asyncio.CancelledError:
pass
thread = self._thread
self._thread = None
self._loop = None
if thread is not None:
self._queue.put(_STOP)
await asyncio.to_thread(thread.join, JOIN_TIMEOUT_SECONDS)
self._flush_remaining()
logger.info(
"background task queue stopped processed=%s failed=%s inline=%s",
@@ -70,24 +93,24 @@ class BackgroundQueue:
def _flush_remaining(self) -> None:
while True:
try:
fn, args, kwargs = self._queue.get_nowait()
except asyncio.QueueEmpty:
item = self._queue.get_nowait()
except queue.Empty:
break
if item is _STOP:
continue
fn, args, kwargs = item
self._execute(fn, args, kwargs)
self._queue.task_done()
async def _drain(self) -> None:
def _worker(self) -> None:
while True:
fn, args, kwargs = await self._queue.get()
try:
item = self._queue.get(timeout=GET_TIMEOUT_SECONDS)
except queue.Empty:
continue
if item is _STOP:
return
fn, args, kwargs = item
self._execute(fn, args, kwargs)
self._queue.task_done()
for _ in range(DRAIN_BATCH - 1):
try:
fn, args, kwargs = self._queue.get_nowait()
except asyncio.QueueEmpty:
break
self._execute(fn, args, kwargs)
self._queue.task_done()
def stats(self) -> dict:
return {