Coverage for baibu/core/views.py: 100%

43 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-10-06 13:07 +0000

1import logging 

2from datetime import datetime 

3 

4from django.conf import settings 

5from django.core.cache import cache 

6from django.db import connection 

7from django.http import HttpRequest 

8from django.http import JsonResponse 

9from django.utils import timezone 

10from django.views.decorators.cache import never_cache 

11 

12from .tasks import HEARTBEAT_CACHE_KEY 

13 

14logger = logging.getLogger(__name__) 

15 

16 

17def _check_database() -> bool: 

18 try: 

19 with connection.cursor() as cursor: 

20 cursor.execute("SELECT 1") 

21 cursor.fetchone() 

22 except Exception: 

23 logger.exception("Health check: database unavailable") 

24 return False 

25 return True 

26 

27 

28def _check_cache() -> bool: 

29 try: 

30 cache.set("core:health-probe", "ok", timeout=10) 

31 return cache.get("core:health-probe") == "ok" 

32 except Exception: 

33 logger.exception("Health check: cache unavailable") 

34 return False 

35 

36 

37def _worker_status() -> str: 

38 """``ok`` if a worker ran the heartbeat task recently, else ``stale`` or ``unknown``.""" 

39 value = cache.get(HEARTBEAT_CACHE_KEY) 

40 if not value: 

41 return "unknown" 

42 try: 

43 last_beat = datetime.fromisoformat(value) 

44 except (TypeError, ValueError): 

45 return "unknown" 

46 age = (timezone.now() - last_beat).total_seconds() 

47 return "ok" if age <= settings.WORKER_HEARTBEAT_STALE_SECONDS else "stale" 

48 

49 

50@never_cache 

51def health(request: HttpRequest) -> JsonResponse: 

52 """Liveness for operators and container health checks. 

53 

54 Returns 503 when the database or cache is down. The worker status is 

55 reported but does not fail the check, so the web container is not 

56 restarted because a worker is down. 

57 """ 

58 database_ok = _check_database() 

59 cache_ok = _check_cache() 

60 healthy = database_ok and cache_ok 

61 return JsonResponse( 

62 { 

63 "status": "ok" if healthy else "error", 

64 "database": "ok" if database_ok else "error", 

65 "cache": "ok" if cache_ok else "error", 

66 "worker": _worker_status(), 

67 }, 

68 status=200 if healthy else 503, 

69 )