fastcache-ai 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastcache_ai/__init__.py +191 -0
- fastcache_ai/_bin/fastcache-engine.jar +0 -0
- fastcache_ai/bootstrap.py +555 -0
- fastcache_ai/client.py +420 -0
- fastcache_ai/codec.py +264 -0
- fastcache_ai/decorator.py +378 -0
- fastcache_ai/errors.py +46 -0
- fastcache_ai/l1.py +234 -0
- fastcache_ai/protocol.py +101 -0
- fastcache_ai/singleflight.py +95 -0
- fastcache_ai/ttl.py +66 -0
- fastcache_ai-1.1.0.dist-info/METADATA +103 -0
- fastcache_ai-1.1.0.dist-info/RECORD +16 -0
- fastcache_ai-1.1.0.dist-info/WHEEL +5 -0
- fastcache_ai-1.1.0.dist-info/licenses/LICENSE +202 -0
- fastcache_ai-1.1.0.dist-info/top_level.txt +1 -0
fastcache_ai/__init__.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""FastCache — a zero-infrastructure cache for AI workloads.
|
|
2
|
+
|
|
3
|
+
Installed as ``fastcache-ai``, imported as ``fastcache_ai``. The import name carries the suffix
|
|
4
|
+
because the bare ``fastcache`` name on PyPI already belongs to an unrelated C implementation of
|
|
5
|
+
``functools.lru_cache``; sharing it would make the two packages overwrite each other on disk.
|
|
6
|
+
|
|
7
|
+
.. code-block:: python
|
|
8
|
+
|
|
9
|
+
from fastcache_ai import fastcache
|
|
10
|
+
|
|
11
|
+
@fastcache(ttl="15m")
|
|
12
|
+
def embed(prompt: str):
|
|
13
|
+
return model.encode(prompt)
|
|
14
|
+
|
|
15
|
+
Importing this package starts a background thread that locates or boots the Java engine. The import itself
|
|
16
|
+
never blocks and never raises: if no JVM can be found, the decorator degrades to calling your function, and
|
|
17
|
+
the reason is available from :func:`info`.
|
|
18
|
+
|
|
19
|
+
Set ``FASTCACHE_AUTOSTART=0`` to skip the background warm-up; the sidecar will then be started lazily on
|
|
20
|
+
first cache use instead.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import logging
|
|
26
|
+
import os
|
|
27
|
+
import threading
|
|
28
|
+
from typing import Any, Dict, Optional
|
|
29
|
+
|
|
30
|
+
from .bootstrap import console_url, ensure_sidecar, shutdown_sidecar
|
|
31
|
+
from .client import FastCacheClient
|
|
32
|
+
from .codec import Codec, describe_capabilities
|
|
33
|
+
from .decorator import build_key, default_client, fastcache, set_default_client, single_flight_stats
|
|
34
|
+
from .errors import (
|
|
35
|
+
FastCacheError,
|
|
36
|
+
ProtocolError,
|
|
37
|
+
SerializationError,
|
|
38
|
+
SidecarStartupError,
|
|
39
|
+
SidecarUnavailable,
|
|
40
|
+
WriteRejected,
|
|
41
|
+
)
|
|
42
|
+
from .l1 import HotKeyCache, NullL1
|
|
43
|
+
from .ttl import format_ttl, parse_ttl
|
|
44
|
+
|
|
45
|
+
__version__ = "1.1.0"
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
"fastcache",
|
|
49
|
+
"FastCacheClient",
|
|
50
|
+
"HotKeyCache",
|
|
51
|
+
"NullL1",
|
|
52
|
+
"Codec",
|
|
53
|
+
"FastCacheError",
|
|
54
|
+
"SidecarUnavailable",
|
|
55
|
+
"SidecarStartupError",
|
|
56
|
+
"ProtocolError",
|
|
57
|
+
"WriteRejected",
|
|
58
|
+
"SerializationError",
|
|
59
|
+
"get",
|
|
60
|
+
"put",
|
|
61
|
+
"set",
|
|
62
|
+
"delete",
|
|
63
|
+
"stats",
|
|
64
|
+
"flush",
|
|
65
|
+
"ping",
|
|
66
|
+
"info",
|
|
67
|
+
"configure",
|
|
68
|
+
"ensure_sidecar",
|
|
69
|
+
"shutdown_sidecar",
|
|
70
|
+
"console_url",
|
|
71
|
+
"dashboard",
|
|
72
|
+
"single_flight_stats",
|
|
73
|
+
"default_client",
|
|
74
|
+
"set_default_client",
|
|
75
|
+
"build_key",
|
|
76
|
+
"parse_ttl",
|
|
77
|
+
"format_ttl",
|
|
78
|
+
"__version__",
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
log = logging.getLogger("fastcache")
|
|
82
|
+
|
|
83
|
+
_startup_error: Optional[BaseException] = None
|
|
84
|
+
_startup_thread: Optional[threading.Thread] = None
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# ---------------------------------------------------------------------------------------------------
|
|
88
|
+
# Module-level convenience API
|
|
89
|
+
# ---------------------------------------------------------------------------------------------------
|
|
90
|
+
|
|
91
|
+
def get(key: str, default: Any = None) -> Any:
|
|
92
|
+
"""Reads a value from the shared client."""
|
|
93
|
+
return default_client().get(key, default)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def put(key: str, value: Any, ttl: Any = None) -> int:
|
|
97
|
+
"""Writes a value through the shared client. Returns the wire status (0 = stored)."""
|
|
98
|
+
return default_client().put(key, value, ttl=ttl)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
#: Redis-style alias for :func:`put`.
|
|
102
|
+
set = put # noqa: A001 - shadowing the builtin is intentional and scoped to this module's namespace
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def delete(key: str) -> bool:
|
|
106
|
+
return default_client().delete(key)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def stats() -> Dict[str, Any]:
|
|
110
|
+
"""Engine, L1 and client telemetry."""
|
|
111
|
+
return default_client().stats()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def flush() -> int:
|
|
115
|
+
"""Drops every cached entry. Mostly useful between test cases."""
|
|
116
|
+
return default_client().flush()
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def ping() -> bool:
|
|
120
|
+
return default_client().ping()
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def configure(**kwargs: Any) -> FastCacheClient:
|
|
124
|
+
"""Replaces the shared client with one built from ``kwargs``.
|
|
125
|
+
|
|
126
|
+
.. code-block:: python
|
|
127
|
+
|
|
128
|
+
fastcache.configure(host="10.0.0.5", port=7431, timeout=2.0)
|
|
129
|
+
fastcache.configure(l1=fastcache.NullL1()) # disable local caching entirely
|
|
130
|
+
"""
|
|
131
|
+
client = FastCacheClient(**kwargs)
|
|
132
|
+
set_default_client(client)
|
|
133
|
+
return client
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def dashboard(open_browser: bool = False) -> Optional[str]:
|
|
137
|
+
"""Returns the management console URL, optionally opening it.
|
|
138
|
+
|
|
139
|
+
.. code-block:: python
|
|
140
|
+
|
|
141
|
+
fastcache.dashboard(open_browser=True) # live savings, memory and hit-rate console
|
|
142
|
+
|
|
143
|
+
Returns None when the console is disabled (``FASTCACHE_METRICS_PORT=off``) or its port was already
|
|
144
|
+
taken — the cache itself is unaffected either way.
|
|
145
|
+
"""
|
|
146
|
+
ensure_sidecar()
|
|
147
|
+
url = console_url()
|
|
148
|
+
if url and open_browser:
|
|
149
|
+
import webbrowser
|
|
150
|
+
|
|
151
|
+
webbrowser.open(url)
|
|
152
|
+
return url
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def info() -> Dict[str, Any]:
|
|
156
|
+
"""Everything needed to diagnose a FastCache problem in one call."""
|
|
157
|
+
from . import bootstrap
|
|
158
|
+
|
|
159
|
+
details = bootstrap.info()
|
|
160
|
+
details["version"] = __version__
|
|
161
|
+
details["codecs"] = describe_capabilities()
|
|
162
|
+
details["autostart_error"] = repr(_startup_error) if _startup_error else None
|
|
163
|
+
details["single_flight"] = single_flight_stats()
|
|
164
|
+
return details
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# ---------------------------------------------------------------------------------------------------
|
|
168
|
+
# Import-time autopilot
|
|
169
|
+
# ---------------------------------------------------------------------------------------------------
|
|
170
|
+
|
|
171
|
+
def _autostart() -> None:
|
|
172
|
+
"""Warms the sidecar in the background.
|
|
173
|
+
|
|
174
|
+
Running on a daemon thread is the point: booting a JVM takes a few hundred milliseconds, and an
|
|
175
|
+
``import`` that blocks that long is one people work around. By the time the first cache call arrives,
|
|
176
|
+
the engine is usually already up; if it is not, the call resolves it synchronously.
|
|
177
|
+
|
|
178
|
+
Failures are recorded, never raised. A missing JDK on a developer laptop must not break
|
|
179
|
+
``import fastcache_ai`` at the top of a training script.
|
|
180
|
+
"""
|
|
181
|
+
global _startup_error
|
|
182
|
+
try:
|
|
183
|
+
ensure_sidecar()
|
|
184
|
+
except BaseException as exc: # noqa: BLE001 - an import must not be able to fail here
|
|
185
|
+
_startup_error = exc
|
|
186
|
+
log.debug("fastcache: sidecar autostart deferred (%s)", exc)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
if os.environ.get("FASTCACHE_AUTOSTART", "1").lower() not in {"0", "false", "no"}:
|
|
190
|
+
_startup_thread = threading.Thread(target=_autostart, name="fastcache-autostart", daemon=True)
|
|
191
|
+
_startup_thread.start()
|
|
Binary file
|