cachify 0.1.0__tar.gz → 0.2.1__tar.gz
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.
- {cachify-0.1.0 → cachify-0.2.1}/LICENSE +21 -21
- {cachify-0.1.0 → cachify-0.2.1}/PKG-INFO +72 -13
- {cachify-0.1.0 → cachify-0.2.1}/README.md +203 -145
- {cachify-0.1.0 → cachify-0.2.1}/cachify/__init__.py +23 -22
- {cachify-0.1.0 → cachify-0.2.1}/cachify/cache.py +116 -116
- {cachify-0.1.0 → cachify-0.2.1}/cachify/config/__init__.py +4 -4
- {cachify-0.1.0 → cachify-0.2.1}/cachify/features/never_die.py +219 -219
- {cachify-0.1.0 → cachify-0.2.1}/cachify/memory_cache.py +37 -37
- {cachify-0.1.0 → cachify-0.2.1}/cachify/redis/__init__.py +19 -19
- {cachify-0.1.0 → cachify-0.2.1}/cachify/redis/config.py +115 -115
- {cachify-0.1.0 → cachify-0.2.1}/cachify/redis/lock.py +232 -232
- {cachify-0.1.0 → cachify-0.2.1}/cachify/redis_cache.py +27 -27
- {cachify-0.1.0 → cachify-0.2.1}/cachify/storage/__init__.py +9 -9
- {cachify-0.1.0 → cachify-0.2.1}/cachify/storage/memory_storage.py +52 -52
- {cachify-0.1.0 → cachify-0.2.1}/cachify/storage/redis_storage.py +138 -138
- {cachify-0.1.0 → cachify-0.2.1}/cachify/types/__init__.py +95 -95
- {cachify-0.1.0 → cachify-0.2.1}/cachify/utils/arguments.py +65 -65
- {cachify-0.1.0 → cachify-0.2.1}/cachify/utils/decorator_factory.py +44 -44
- {cachify-0.1.0 → cachify-0.2.1}/cachify/utils/functions.py +10 -10
- {cachify-0.1.0 → cachify-0.2.1}/cachify/utils/locks.py +6 -6
- {cachify-0.1.0 → cachify-0.2.1}/pyproject.toml +54 -48
- {cachify-0.1.0 → cachify-0.2.1}/cachify/features/__init__.py +0 -0
- {cachify-0.1.0 → cachify-0.2.1}/cachify/utils/__init__.py +0 -0
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c)
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pulsar Finance
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: cachify
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: A simple cache library with sync/async support, Memory and Redis backend
|
|
5
|
-
Home-page: https://github.com/PulsarDataSolutions/cachify
|
|
6
5
|
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
7
|
Keywords: cachify,cache,caching,redis,async,decorator,memoization
|
|
8
8
|
Author: dynalz
|
|
9
9
|
Author-email: git@pulsar.finance
|
|
@@ -20,6 +20,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
20
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
21
|
Classifier: Typing :: Typed
|
|
22
22
|
Requires-Dist: redis[hiredis] (>5.0.0)
|
|
23
|
+
Project-URL: Homepage, https://github.com/PulsarDataSolutions/cachify
|
|
23
24
|
Project-URL: Repository, https://github.com/PulsarDataSolutions/cachify
|
|
24
25
|
Description-Content-Type: text/markdown
|
|
25
26
|
|
|
@@ -27,6 +28,19 @@ Description-Content-Type: text/markdown
|
|
|
27
28
|
|
|
28
29
|
A simple and robust caching library for Python functions, supporting both synchronous and asynchronous code.
|
|
29
30
|
|
|
31
|
+
## Table of Contents
|
|
32
|
+
|
|
33
|
+
- [Features](#features)
|
|
34
|
+
- [Installation](#installation)
|
|
35
|
+
- [Usage](#usage)
|
|
36
|
+
- [Basic Usage](#basic-usage)
|
|
37
|
+
- [Redis Cache](#redis-cache)
|
|
38
|
+
- [Never Die Cache](#never-die-cache)
|
|
39
|
+
- [Skip Cache](#skip-cache)
|
|
40
|
+
- [Testing](#testing)
|
|
41
|
+
- [Contributing](#contributing)
|
|
42
|
+
- [License](#license)
|
|
43
|
+
|
|
30
44
|
## Features
|
|
31
45
|
|
|
32
46
|
- Cache function results based on function ID and arguments
|
|
@@ -40,12 +54,14 @@ A simple and robust caching library for Python functions, supporting both synchr
|
|
|
40
54
|
## Installation
|
|
41
55
|
|
|
42
56
|
```bash
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
# Using pip
|
|
58
|
+
pip install cachify
|
|
59
|
+
|
|
60
|
+
# Using poetry
|
|
61
|
+
poetry add cachify
|
|
46
62
|
|
|
47
|
-
#
|
|
48
|
-
|
|
63
|
+
# Using uv
|
|
64
|
+
uv add cachify
|
|
49
65
|
```
|
|
50
66
|
|
|
51
67
|
## Usage
|
|
@@ -56,18 +72,57 @@ poetry install
|
|
|
56
72
|
from cachify import cache
|
|
57
73
|
|
|
58
74
|
# Cache function in sync functions
|
|
59
|
-
@cache(ttl=60)
|
|
75
|
+
@cache(ttl=60) # ttl in seconds
|
|
60
76
|
def expensive_calculation(a, b):
|
|
61
77
|
# Some expensive operation
|
|
62
78
|
return a + b
|
|
63
79
|
|
|
64
80
|
# And async functions
|
|
65
|
-
@cache(ttl=3600)
|
|
81
|
+
@cache(ttl=3600) # ttl in seconds
|
|
66
82
|
async def another_calculation(url):
|
|
67
83
|
# Some expensive IO call
|
|
68
84
|
return await httpx.get(url).json()
|
|
69
85
|
```
|
|
70
86
|
|
|
87
|
+
### Decorator Parameters
|
|
88
|
+
|
|
89
|
+
| Parameter | Type | Default | Description |
|
|
90
|
+
| ---------------- | ----------------- | ------- | ---------------------------------------------------- |
|
|
91
|
+
| `ttl` | `int \| float` | `300` | Time to live for cached items in seconds |
|
|
92
|
+
| `never_die` | `bool` | `False` | If True, cache refreshes automatically in background |
|
|
93
|
+
| `cache_key_func` | `Callable` | `None` | Custom function to generate cache keys |
|
|
94
|
+
| `ignore_fields` | `tuple[str, ...]` | `()` | Function parameters to exclude from cache key |
|
|
95
|
+
|
|
96
|
+
### Custom Cache Key Function
|
|
97
|
+
|
|
98
|
+
Use `cache_key_func` when you need custom control over how cache keys are generated:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from cachify import cache
|
|
102
|
+
|
|
103
|
+
def custom_key(args: tuple, kwargs: dict) -> str:
|
|
104
|
+
user_id = kwargs.get("user_id") or args[0]
|
|
105
|
+
return f"user:{user_id}"
|
|
106
|
+
|
|
107
|
+
@cache(ttl=60, cache_key_func=custom_key)
|
|
108
|
+
def get_user_profile(user_id: int):
|
|
109
|
+
return fetch_from_database(user_id)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Ignore Fields
|
|
113
|
+
|
|
114
|
+
Use `ignore_fields` to exclude specific parameters from the cache key. Useful when some arguments don't affect the result:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from cachify import cache
|
|
118
|
+
|
|
119
|
+
@cache(ttl=300, ignore_fields=("logger", "request_id"))
|
|
120
|
+
def fetch_data(query: str, logger: Logger, request_id: str):
|
|
121
|
+
# Cache key only uses 'query', ignoring logger and request_id
|
|
122
|
+
logger.info(f"Fetching data for request {request_id}")
|
|
123
|
+
return database.execute(query)
|
|
124
|
+
```
|
|
125
|
+
|
|
71
126
|
### Redis Cache
|
|
72
127
|
|
|
73
128
|
For distributed caching across multiple processes or machines, use `rcache`:
|
|
@@ -79,7 +134,7 @@ from cachify import setup_redis_config, rcache
|
|
|
79
134
|
# Configure Redis (call once at startup)
|
|
80
135
|
setup_redis_config(
|
|
81
136
|
sync_client=redis.from_url("redis://localhost:6379/0"),
|
|
82
|
-
key_prefix="myapp", # default: "
|
|
137
|
+
key_prefix="myapp", # default: "cachify", prefix searchable on redis "PREFIX:*"
|
|
83
138
|
lock_timeout=10, # default: 10, maximum lock lifetime in seconds
|
|
84
139
|
on_error="silent", # "silent" (default) or "raise" in case of redis errors
|
|
85
140
|
)
|
|
@@ -94,7 +149,7 @@ import redis.asyncio as aredis
|
|
|
94
149
|
setup_redis_config(async_client=aredis.from_url("redis://localhost:6379/0"))
|
|
95
150
|
|
|
96
151
|
@rcache(ttl=300)
|
|
97
|
-
def get_user_async(user_id: int) -> dict:
|
|
152
|
+
async def get_user_async(user_id: int) -> dict:
|
|
98
153
|
return await fetch_from_database(user_id)
|
|
99
154
|
```
|
|
100
155
|
|
|
@@ -165,7 +220,11 @@ Run the test scripts
|
|
|
165
220
|
poetry run python -m pytest
|
|
166
221
|
```
|
|
167
222
|
|
|
223
|
+
## Contributing
|
|
224
|
+
|
|
225
|
+
Contributions are welcome! Feel free to open an issue or submit a pull request.
|
|
226
|
+
|
|
168
227
|
## License
|
|
169
228
|
|
|
170
|
-
MIT
|
|
229
|
+
This project is licensed under the MIT License - see the [LICENSE](https://github.com/PulsarDataSolutions/cachify/blob/master/LICENSE) file for details.
|
|
171
230
|
|
|
@@ -1,145 +1,203 @@
|
|
|
1
|
-
# Python Cachify Library
|
|
2
|
-
|
|
3
|
-
A simple and robust caching library for Python functions, supporting both synchronous and asynchronous code.
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
#
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
#
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
1
|
+
# Python Cachify Library
|
|
2
|
+
|
|
3
|
+
A simple and robust caching library for Python functions, supporting both synchronous and asynchronous code.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Features](#features)
|
|
8
|
+
- [Installation](#installation)
|
|
9
|
+
- [Usage](#usage)
|
|
10
|
+
- [Basic Usage](#basic-usage)
|
|
11
|
+
- [Redis Cache](#redis-cache)
|
|
12
|
+
- [Never Die Cache](#never-die-cache)
|
|
13
|
+
- [Skip Cache](#skip-cache)
|
|
14
|
+
- [Testing](#testing)
|
|
15
|
+
- [Contributing](#contributing)
|
|
16
|
+
- [License](#license)
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- Cache function results based on function ID and arguments
|
|
21
|
+
- Supports both synchronous and asynchronous functions
|
|
22
|
+
- Thread-safe locking to prevent duplicate cached function calls
|
|
23
|
+
- Configurable Time-To-Live (TTL) for cached items
|
|
24
|
+
- "Never Die" mode for functions that should keep cache refreshed automatically
|
|
25
|
+
- Skip cache functionality to force fresh function execution while updating cache
|
|
26
|
+
- Redis cache for distributed caching across multiple processes/machines
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Using pip
|
|
32
|
+
pip install cachify
|
|
33
|
+
|
|
34
|
+
# Using poetry
|
|
35
|
+
poetry add cachify
|
|
36
|
+
|
|
37
|
+
# Using uv
|
|
38
|
+
uv add cachify
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
### Basic Usage
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from cachify import cache
|
|
47
|
+
|
|
48
|
+
# Cache function in sync functions
|
|
49
|
+
@cache(ttl=60) # ttl in seconds
|
|
50
|
+
def expensive_calculation(a, b):
|
|
51
|
+
# Some expensive operation
|
|
52
|
+
return a + b
|
|
53
|
+
|
|
54
|
+
# And async functions
|
|
55
|
+
@cache(ttl=3600) # ttl in seconds
|
|
56
|
+
async def another_calculation(url):
|
|
57
|
+
# Some expensive IO call
|
|
58
|
+
return await httpx.get(url).json()
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Decorator Parameters
|
|
62
|
+
|
|
63
|
+
| Parameter | Type | Default | Description |
|
|
64
|
+
| ---------------- | ----------------- | ------- | ---------------------------------------------------- |
|
|
65
|
+
| `ttl` | `int \| float` | `300` | Time to live for cached items in seconds |
|
|
66
|
+
| `never_die` | `bool` | `False` | If True, cache refreshes automatically in background |
|
|
67
|
+
| `cache_key_func` | `Callable` | `None` | Custom function to generate cache keys |
|
|
68
|
+
| `ignore_fields` | `tuple[str, ...]` | `()` | Function parameters to exclude from cache key |
|
|
69
|
+
|
|
70
|
+
### Custom Cache Key Function
|
|
71
|
+
|
|
72
|
+
Use `cache_key_func` when you need custom control over how cache keys are generated:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from cachify import cache
|
|
76
|
+
|
|
77
|
+
def custom_key(args: tuple, kwargs: dict) -> str:
|
|
78
|
+
user_id = kwargs.get("user_id") or args[0]
|
|
79
|
+
return f"user:{user_id}"
|
|
80
|
+
|
|
81
|
+
@cache(ttl=60, cache_key_func=custom_key)
|
|
82
|
+
def get_user_profile(user_id: int):
|
|
83
|
+
return fetch_from_database(user_id)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Ignore Fields
|
|
87
|
+
|
|
88
|
+
Use `ignore_fields` to exclude specific parameters from the cache key. Useful when some arguments don't affect the result:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from cachify import cache
|
|
92
|
+
|
|
93
|
+
@cache(ttl=300, ignore_fields=("logger", "request_id"))
|
|
94
|
+
def fetch_data(query: str, logger: Logger, request_id: str):
|
|
95
|
+
# Cache key only uses 'query', ignoring logger and request_id
|
|
96
|
+
logger.info(f"Fetching data for request {request_id}")
|
|
97
|
+
return database.execute(query)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Redis Cache
|
|
101
|
+
|
|
102
|
+
For distributed caching across multiple processes or machines, use `rcache`:
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
import redis
|
|
106
|
+
from cachify import setup_redis_config, rcache
|
|
107
|
+
|
|
108
|
+
# Configure Redis (call once at startup)
|
|
109
|
+
setup_redis_config(
|
|
110
|
+
sync_client=redis.from_url("redis://localhost:6379/0"),
|
|
111
|
+
key_prefix="myapp", # default: "cachify", prefix searchable on redis "PREFIX:*"
|
|
112
|
+
lock_timeout=10, # default: 10, maximum lock lifetime in seconds
|
|
113
|
+
on_error="silent", # "silent" (default) or "raise" in case of redis errors
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
@rcache(ttl=300)
|
|
117
|
+
def get_user(user_id: int) -> dict:
|
|
118
|
+
return fetch_from_database(user_id)
|
|
119
|
+
|
|
120
|
+
# Async version
|
|
121
|
+
import redis.asyncio as aredis
|
|
122
|
+
|
|
123
|
+
setup_redis_config(async_client=aredis.from_url("redis://localhost:6379/0"))
|
|
124
|
+
|
|
125
|
+
@rcache(ttl=300)
|
|
126
|
+
async def get_user_async(user_id: int) -> dict:
|
|
127
|
+
return await fetch_from_database(user_id)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Never Die Cache
|
|
131
|
+
|
|
132
|
+
The `never_die` feature ensures that cached values never expire by automatically refreshing them in the background:
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
# Cache with never_die (automatic refresh)
|
|
136
|
+
@cache(ttl=300, never_die=True)
|
|
137
|
+
def critical_operation(data_id: str):
|
|
138
|
+
# Expensive operation that should always be available from cache
|
|
139
|
+
return fetch_data_from_database(data_id)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**How Never Die Works:**
|
|
143
|
+
|
|
144
|
+
1. When a function with `never_die=True` is first called, the result is cached
|
|
145
|
+
2. A background thread monitors all `never_die` functions
|
|
146
|
+
3. On cache expiration (TTL), the function is automatically called again
|
|
147
|
+
4. The cache is updated with the new result
|
|
148
|
+
5. If the refresh operation fails, the existing cached value is preserved
|
|
149
|
+
6. Clients always get fast response times by reading from cache
|
|
150
|
+
|
|
151
|
+
**Benefits:**
|
|
152
|
+
|
|
153
|
+
- Cache is always "warm" and ready to serve
|
|
154
|
+
- No user request ever has to wait for the expensive operation
|
|
155
|
+
- If a dependency service from the cached function goes down temporarily, the last successful result is still available
|
|
156
|
+
- Perfect for critical operations where latency must be minimized
|
|
157
|
+
|
|
158
|
+
### Skip Cache
|
|
159
|
+
|
|
160
|
+
The `skip_cache` feature allows you to bypass reading from cache while still updating it with fresh results:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
@cache(ttl=300)
|
|
164
|
+
def get_user_data(user_id):
|
|
165
|
+
# Expensive operation to fetch user data
|
|
166
|
+
return fetch_from_database(user_id)
|
|
167
|
+
|
|
168
|
+
# Normal call - uses cache if available
|
|
169
|
+
user = get_user_data(123)
|
|
170
|
+
# Force fresh execution while updating cache
|
|
171
|
+
fresh_user = get_user_data(123, skip_cache=True)
|
|
172
|
+
# Next normal call will get the updated cached value
|
|
173
|
+
updated_user = get_user_data(123)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**How Skip Cache Works:**
|
|
177
|
+
|
|
178
|
+
1. When `skip_cache=True` is passed, the function bypasses reading from cache
|
|
179
|
+
2. The function executes normally and returns fresh results
|
|
180
|
+
3. The fresh result is stored in the cache, updating any existing cached value
|
|
181
|
+
4. Subsequent calls without `skip_cache=True` will use the updated cached value
|
|
182
|
+
5. The TTL timer resets from when the cache last was updated
|
|
183
|
+
|
|
184
|
+
**Benefits:**
|
|
185
|
+
|
|
186
|
+
- Force refresh of potentially stale data while keeping cache warm
|
|
187
|
+
- Ensuring fresh data for critical operations while maintaining cache for other calls
|
|
188
|
+
|
|
189
|
+
## Testing
|
|
190
|
+
|
|
191
|
+
Run the test scripts
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
poetry run python -m pytest
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Contributing
|
|
198
|
+
|
|
199
|
+
Contributions are welcome! Feel free to open an issue or submit a pull request.
|
|
200
|
+
|
|
201
|
+
## License
|
|
202
|
+
|
|
203
|
+
This project is licensed under the MIT License - see the [LICENSE](https://github.com/PulsarDataSolutions/cachify/blob/master/LICENSE) file for details.
|
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
from .
|
|
2
|
-
|
|
3
|
-
from .
|
|
4
|
-
from .
|
|
5
|
-
from .
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
|
|
1
|
+
from importlib.metadata import version
|
|
2
|
+
|
|
3
|
+
from .features.never_die import clear_never_die_registry
|
|
4
|
+
from .memory_cache import cache
|
|
5
|
+
from .redis import DEFAULT_KEY_PREFIX, get_redis_config, reset_redis_config, setup_redis_config
|
|
6
|
+
from .redis_cache import redis_cache
|
|
7
|
+
from .types import CacheKwargs
|
|
8
|
+
|
|
9
|
+
__version__ = version("cachify")
|
|
10
|
+
|
|
11
|
+
rcache = redis_cache
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"__version__",
|
|
15
|
+
"cache",
|
|
16
|
+
"rcache",
|
|
17
|
+
"redis_cache",
|
|
18
|
+
"setup_redis_config",
|
|
19
|
+
"get_redis_config",
|
|
20
|
+
"reset_redis_config",
|
|
21
|
+
"DEFAULT_KEY_PREFIX",
|
|
22
|
+
"CacheKwargs",
|
|
23
|
+
]
|