Coverage for fastblocks/adapters/sitemap/cached.py: 0%
78 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-21 04:50 -0700
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-21 04:50 -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):
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 @depends.inject
33 def items(self) -> list[str]:
34 try:
35 routes_adapter = depends.get("routes")
36 if hasattr(routes_adapter, "routes"):
37 route_paths = [r.path for r in routes_adapter.routes]
38 debug(f"CachedSitemap: Cached {len(route_paths)} routes")
39 return route_paths
40 return []
41 except Exception as e:
42 debug(f"CachedSitemap: Error getting routes: {e}")
43 return []
45 def location(self, item: str) -> str:
46 return item
48 def changefreq(self, item: str) -> str:
49 return self.config.change_freq
51 def priority(self, item: str) -> float:
52 if item == "/":
53 return 1.0
54 segments = len([s for s in item.split("/") if s])
55 if segments == 1:
56 return 0.8
57 elif segments == 2:
58 return 0.6
59 else:
60 return 0.4
62 async def _background_refresh(self) -> None:
63 strategy_options = self.config.strategy_options
64 background_refresh = strategy_options.get("background_refresh", True)
65 if not background_refresh:
66 return
67 debug("CachedSitemap: Starting background refresh task")
68 while True:
69 try:
70 await asyncio.sleep(self.config.cache_ttl)
71 debug("CachedSitemap: Refreshing sitemap cache")
72 except asyncio.CancelledError:
73 debug("CachedSitemap: Background refresh cancelled")
74 break
75 except Exception as e:
76 debug(f"CachedSitemap: Background refresh error: {e}")
77 await asyncio.sleep(300)
79 async def init(self) -> None:
80 if not self.config.domain:
81 msg = "domain must be set in sitemap settings"
82 raise ValueError(msg)
83 extended_ttl = self.config.cache_ttl * 2
84 self.sitemap = SitemapApp(
85 self,
86 domain=self.config.domain,
87 cache_ttl=extended_ttl,
88 )
89 strategy_options = self.config.strategy_options
90 if strategy_options.get("background_refresh", True):
91 self._background_task = asyncio.create_task(self._background_refresh())
92 debug(f"CachedSitemap: Initialized with domain={self.config.domain}")
94 async def cleanup(self) -> None:
95 if self._background_task:
96 self._background_task.cancel()
97 try:
98 await self._background_task
99 except asyncio.CancelledError:
100 pass
103Sitemap = CachedSitemap
105MODULE_ID = UUID("01937d86-cfa2-73b4-0675-901234567823")
106MODULE_STATUS = AdapterStatus.STABLE
108with suppress(Exception):
109 depends.set(Sitemap)