解决极速成片问题

This commit is contained in:
Azmat@qq.com
2026-08-26 09:19:53 +08:00
parent 43d0b088e4
commit 245525ec53
7 changed files with 114 additions and 8 deletions
+37
View File
@@ -29,6 +29,7 @@ _FAIL_TTL = 5.0
_cache = {"ok": False, "expires": 0.0}
# True / False / None(inspect 没答上来,不当成「未部署」)
_registered_task_cache: dict[str, tuple[bool | None, float]] = {}
_queue_cache: dict[str, tuple[bool | None, float]] = {}
def _task_name_listed(task_name: str, task_names) -> bool:
@@ -77,6 +78,42 @@ def celery_worker_available() -> bool:
return ok
def _inspect_queue_consumed(queue_name: str) -> bool | None:
"""True 有 worker 在听该队列 / False 在线 worker 都不听 / None 问不到。"""
try:
from airshelf.celery import app as celery_app
active_queues = celery_app.control.inspect(timeout=2.5).active_queues()
except Exception: # noqa: BLE001 — inspect 失败不能当成「没人听」
return None
if not active_queues:
return None
found_any_queue = False
for queues in active_queues.values():
for item in queues or []:
found_any_queue = True
name = item.get("name") if isinstance(item, dict) else str(item)
if name == queue_name:
return True
if found_any_queue:
return False
return None
def worker_consumes_queue(queue_name: str) -> bool | None:
"""线上 worker 默认只听 celery;极速成片发到 airshelf.quick 时用来决定要不要本机兜底。"""
if getattr(settings, "CELERY_TASK_ALWAYS_EAGER", False):
return True
now = time.monotonic()
cached = _queue_cache.get(queue_name)
if cached and now < cached[1]:
return cached[0]
available = _inspect_queue_consumed(queue_name)
ttl = _OK_TTL if available else _FAIL_TTL
_queue_cache[queue_name] = (available, now + ttl)
return available
def require_worker() -> None:
"""生成类提交入口的前置检查:无 worker 直接 503,不让任务出门。"""
if not celery_worker_available():
+13 -1
View File
@@ -4,16 +4,18 @@ from django.test import SimpleTestCase, override_settings
from rest_framework.exceptions import APIException
from apps.common import celery_health
from apps.common.celery_health import require_worker_task
from apps.common.celery_health import require_worker_task, worker_consumes_queue
class RequireWorkerTaskTests(SimpleTestCase):
def setUp(self):
celery_health._registered_task_cache.clear()
celery_health._queue_cache.clear()
celery_health._cache["expires"] = 0.0
def tearDown(self):
celery_health._registered_task_cache.clear()
celery_health._queue_cache.clear()
celery_health._cache["expires"] = 0.0
def test_registered_name_accepts_short_name_and_rate_suffix(self):
@@ -39,3 +41,13 @@ class RequireWorkerTaskTests(SimpleTestCase):
self.assertEqual(raised.exception.status_code, 503)
self.assertIn("重启", str(raised.exception.detail))
self.assertNotIn("正在升级", str(raised.exception.detail))
@override_settings(CELERY_TASK_ALWAYS_EAGER=False)
@patch("apps.common.celery_health._inspect_queue_consumed", return_value=False)
def test_missing_quick_queue_is_detected(self, _inspect):
self.assertIs(worker_consumes_queue("airshelf.quick"), False)
@override_settings(CELERY_TASK_ALWAYS_EAGER=False)
@patch("apps.common.celery_health._inspect_queue_consumed", return_value=None)
def test_unknown_queue_inspect_does_not_pretend_missing(self, _inspect):
self.assertIsNone(worker_consumes_queue("airshelf.quick"))