Coverage for fastblocks/adapters/sitemap/cached.py: 0%
77 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-09 00:47 -0700
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-09 00:47 -0700
1"""FastBlocks Cached Sitemap Adapter.
3Heavy caching wrapper for sitemap generation with background refresh
4and persistent storage for high-performance sitemap serving.
5"""
7import asyncio
8import typing as t
9from contextlib import suppress
10from uuid import UUID
12from acb.adapters import AdapterStatus
13from acb.debug import debug
14from acb.depends import depends
16from ._base import SitemapBase, SitemapBaseSettings
17from .core import BaseSitemap, SitemapApp
20class CachedSitemapSettings(SitemapBaseSettings):
21 pass
24class CachedSitemap(BaseSitemap[str], SitemapBase): # type: ignore[override]
25 sitemap: SitemapApp | None = None
26 _background_task: asyncio.Task[t.Any] | None = None
28 def __init__(self) -> None:
29 super().__init__()
30 self._underlying_adapter = None
32 async def items(self) -> t.Any:
33 try:
34 routes_adapter = depends.get("routes")
35 if hasattr(routes_adapter, "routes"):
36 route_paths = [r.path for r in routes_adapter.routes]
37 debug(f"CachedSitemap: Cached {len(route_paths)} routes")
38 return route_paths
39 return []
40 except Exception as e:
41 debug(f"CachedSitemap: Error getting routes: {e}")
42 return []
44 def location(self, item: str) -> str:
45 return item
47 def changefreq(self, item: str) -> str:
48 return t.cast(str, self.config.change_freq)
50 def priority(self, item: str) -> float:
51 if item == "/":
52 return 1.0
53 segments = len([s for s in item.split("/") if s])
54 if segments == 1:
55 return 0.8
56 if segments == 2:
57 return 0.6
58 return 0.4
60 async def _background_refresh(self) -> None:
61 strategy_options = self.config.strategy_options
62 background_refresh = strategy_options.get("background_refresh", True)
63 if not background_refresh:
64 return
65 debug("CachedSitemap: Starting background refresh task")
66 while True:
67 try:
68 await asyncio.sleep(self.config.cache_ttl)
69 debug("CachedSitemap: Refreshing sitemap cache")
70 except asyncio.CancelledError:
71 debug("CachedSitemap: Background refresh cancelled")
72 break
73 except Exception as e:
74 debug(f"CachedSitemap: Background refresh error: {e}")
75 await asyncio.sleep(300)
77 async def init(self) -> None:
78 if not self.config.domain:
79 msg = "domain must be set in sitemap settings"
80 raise ValueError(msg)
81 extended_ttl = self.config.cache_ttl * 2
82 self.sitemap = SitemapApp(
83 self,
84 domain=self.config.domain,
85 cache_ttl=extended_ttl,
86 )
87 strategy_options = self.config.strategy_options
88 if strategy_options.get("background_refresh", True):
89 self._background_task = asyncio.create_task(self._background_refresh())
90 debug(f"CachedSitemap: Initialized with domain={self.config.domain}")
92 async def cleanup(self) -> None:
93 if self._background_task:
94 self._background_task.cancel()
95 try:
96 await self._background_task
97 except asyncio.CancelledError:
98 pass
101Sitemap = CachedSitemap
103MODULE_ID = UUID("01937d86-cfa2-73b4-0675-901234567823")
104MODULE_STATUS = AdapterStatus.STABLE
106with suppress(Exception):
107 depends.set(Sitemap)