redis-allocator 0.3.2__py3-none-any.whl → 0.4.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.
- redis_allocator/_version.py +1 -1
- redis_allocator/allocator.py +43 -12
- {redis_allocator-0.3.2.dist-info → redis_allocator-0.4.0.dist-info}/METADATA +5 -5
- {redis_allocator-0.3.2.dist-info → redis_allocator-0.4.0.dist-info}/RECORD +8 -8
- tests/conftest.py +1 -0
- {redis_allocator-0.3.2.dist-info → redis_allocator-0.4.0.dist-info}/WHEEL +0 -0
- {redis_allocator-0.3.2.dist-info → redis_allocator-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {redis_allocator-0.3.2.dist-info → redis_allocator-0.4.0.dist-info}/top_level.txt +0 -0
redis_allocator/_version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.
|
1
|
+
__version__ = '0.4.0'
|
redis_allocator/allocator.py
CHANGED
@@ -97,7 +97,7 @@ class RedisAllocatableClass(ABC):
|
|
97
97
|
|
98
98
|
def open(self):
|
99
99
|
"""Open the object."""
|
100
|
-
|
100
|
+
return self
|
101
101
|
|
102
102
|
def close(self):
|
103
103
|
"""close the object."""
|
@@ -162,6 +162,7 @@ class RedisAllocatorObject(Generic[U]):
|
|
162
162
|
"""Open the object."""
|
163
163
|
if self.obj is not None:
|
164
164
|
self.obj.open()
|
165
|
+
return self
|
165
166
|
|
166
167
|
def close(self):
|
167
168
|
"""Kill the object."""
|
@@ -174,21 +175,42 @@ class RedisAllocatorObject(Generic[U]):
|
|
174
175
|
return self.obj.is_healthy()
|
175
176
|
return True
|
176
177
|
|
177
|
-
def
|
178
|
+
def set_healthy(self, duration: Timeout = 3600):
|
179
|
+
"""Set the object as healthy."""
|
180
|
+
if self.obj is not None and self.obj.name is not None:
|
181
|
+
self.allocator.update_soft_bind(self.obj.name, self.key, duration)
|
182
|
+
if self.allocator.shared:
|
183
|
+
self.allocator.unlock(self.key)
|
184
|
+
|
185
|
+
def set_unhealthy(self, duration: Timeout = 3600):
|
178
186
|
"""Set the object as unhealthy."""
|
179
187
|
if self.obj is not None and self.obj.name is not None:
|
180
188
|
self.allocator.unbind_soft_bind(self.obj.name)
|
181
189
|
self.allocator.update(self.key, timeout=duration)
|
182
190
|
|
183
|
-
def refresh(self, timeout: Timeout = 120):
|
191
|
+
def refresh(self, timeout: Timeout = 120, cache_timeout: Timeout = 3600):
|
184
192
|
"""Refresh the object."""
|
185
193
|
self.close()
|
186
194
|
new_obj = self.allocator.policy.malloc(self.allocator, timeout=timeout,
|
187
|
-
obj=self.obj, params=self.params
|
195
|
+
obj=self.obj, params=self.params,
|
196
|
+
cache_timeout=cache_timeout)
|
188
197
|
if new_obj is not None:
|
189
198
|
self.obj = new_obj.obj
|
190
199
|
self.key = new_obj.key
|
191
200
|
self.params = new_obj.params
|
201
|
+
self.open()
|
202
|
+
|
203
|
+
def refresh_until_healthy(self, timeout: Timeout = 120, max_attempts: int = 10, lock_duration: Timeout = 3600, cache_timeout: Timeout = 3600):
|
204
|
+
"""Refresh the object until it is healthy."""
|
205
|
+
for _ in range(max_attempts):
|
206
|
+
try:
|
207
|
+
if self.is_healthy():
|
208
|
+
return
|
209
|
+
except Exception as e:
|
210
|
+
logger.error(f"Error checking health of {self.key}: {e}")
|
211
|
+
self.set_unhealthy(lock_duration)
|
212
|
+
self.refresh(timeout, cache_timeout)
|
213
|
+
raise RuntimeError("the objects is still unhealthy after %d attempts", max_attempts)
|
192
214
|
|
193
215
|
@property
|
194
216
|
def unique_id(self) -> str:
|
@@ -282,9 +304,11 @@ class RedisAllocatorPolicy(ABC):
|
|
282
304
|
|
283
305
|
def check_health_once(self, r_obj: RedisAllocatorObject, duration: int = 3600) -> bool:
|
284
306
|
"""Check the health of the object."""
|
285
|
-
with contextlib.closing(r_obj):
|
307
|
+
with contextlib.closing(r_obj.open()):
|
286
308
|
try:
|
287
309
|
if r_obj.is_healthy():
|
310
|
+
if r_obj.allocator.shared:
|
311
|
+
r_obj.allocator.unlock(r_obj.key) # set the key as free
|
288
312
|
return True
|
289
313
|
else:
|
290
314
|
r_obj.set_unhealthy(duration)
|
@@ -308,6 +332,7 @@ class RedisAllocatorPolicy(ABC):
|
|
308
332
|
A tuple containing the number of healthy and unhealthy items in the allocator
|
309
333
|
"""
|
310
334
|
with ThreadPoolExecutor(max_workers=max_threads) as executor:
|
335
|
+
inputs = []
|
311
336
|
for key in allocator.keys():
|
312
337
|
if params_fn is not None:
|
313
338
|
params = params_fn(key)
|
@@ -317,9 +342,11 @@ class RedisAllocatorPolicy(ABC):
|
|
317
342
|
obj = obj_fn(key)
|
318
343
|
else:
|
319
344
|
obj = None
|
320
|
-
|
321
|
-
|
322
|
-
|
345
|
+
inputs.append(RedisAllocatorObject(allocator, key, obj, params))
|
346
|
+
results = list(executor.map(self.check_health_once, inputs, timeout=max_threads * lock_duration / (len(inputs) + 1)))
|
347
|
+
healthy = sum(results)
|
348
|
+
unhealthy = len(results) - healthy
|
349
|
+
return healthy, unhealthy
|
323
350
|
|
324
351
|
|
325
352
|
class DefaultRedisAllocatorPolicy(RedisAllocatorPolicy):
|
@@ -346,7 +373,8 @@ class DefaultRedisAllocatorPolicy(RedisAllocatorPolicy):
|
|
346
373
|
"""
|
347
374
|
|
348
375
|
def __init__(self, gc_count: int = 5, update_interval: int = 300,
|
349
|
-
expiry_duration: int = -1, updater: Optional[RedisAllocatorUpdater] = None
|
376
|
+
expiry_duration: int = -1, updater: Optional[RedisAllocatorUpdater] = None,
|
377
|
+
auto_close: bool = False):
|
350
378
|
"""Initialize the default allocation policy.
|
351
379
|
|
352
380
|
Args:
|
@@ -354,6 +382,7 @@ class DefaultRedisAllocatorPolicy(RedisAllocatorPolicy):
|
|
354
382
|
update_interval: Interval in seconds between pool updates
|
355
383
|
expiry_duration: Default timeout for pool items (-1 means no timeout)
|
356
384
|
updater: Optional updater for refreshing the pool's keys
|
385
|
+
auto_close: If True, the allocator will automatically close the object when it is not unique
|
357
386
|
"""
|
358
387
|
self.gc_count = gc_count
|
359
388
|
self.update_interval: float = update_interval
|
@@ -362,6 +391,7 @@ class DefaultRedisAllocatorPolicy(RedisAllocatorPolicy):
|
|
362
391
|
self._allocator: Optional[weakref.ReferenceType['RedisAllocator']] = None
|
363
392
|
self._update_lock_key: Optional[str] = None
|
364
393
|
self.objects: weakref.WeakValueDictionary[str, RedisAllocatorObject] = weakref.WeakValueDictionary()
|
394
|
+
self.auto_close = auto_close
|
365
395
|
|
366
396
|
def initialize(self, allocator: 'RedisAllocator'):
|
367
397
|
"""Initialize the policy with an allocator instance.
|
@@ -407,9 +437,10 @@ class DefaultRedisAllocatorPolicy(RedisAllocatorPolicy):
|
|
407
437
|
key = allocator.malloc_key(timeout, obj_name,
|
408
438
|
cache_timeout=cache_timeout)
|
409
439
|
alloc_obj = RedisAllocatorObject(allocator, key, obj, params)
|
410
|
-
|
411
|
-
|
412
|
-
old_obj
|
440
|
+
if self.auto_close:
|
441
|
+
old_obj = self.objects.get(alloc_obj.unique_id, None)
|
442
|
+
if old_obj is not None:
|
443
|
+
old_obj.close()
|
413
444
|
self.objects[alloc_obj.unique_id] = alloc_obj
|
414
445
|
return alloc_obj
|
415
446
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: redis-allocator
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.4.0
|
4
4
|
Summary: Redis-based resource allocation system.
|
5
5
|
Home-page: https://github.com/invoker-bot/RedisAllocator-python
|
6
6
|
Author: Invoker Bot
|
@@ -230,7 +230,7 @@ if allocated_obj:
|
|
230
230
|
|
231
231
|
# Using soft binding (associates a name with a resource)
|
232
232
|
allocator.update_soft_bind("worker-1", "resource-1")
|
233
|
-
#
|
233
|
+
# Unbind soft binding
|
234
234
|
allocator.unbind_soft_bind("worker-1")
|
235
235
|
|
236
236
|
# Garbage collection (reclaims unused resources)
|
@@ -291,9 +291,9 @@ graph TD
|
|
291
291
|
|
292
292
|
subgraph "PoolHash Contents (Doubly-Linked Free List)"
|
293
293
|
Key1 --> Key2["Key2: Key1||Key3||Expiry"]
|
294
|
-
Key2 --> Key3["Key3: Key2
|
295
|
-
Key3 -->
|
296
|
-
KeyN_1[
|
294
|
+
Key2 --> Key3["Key3: Key2||Key4||Expiry"]
|
295
|
+
Key3 --> Key4["Key4: Key3||Key5||Expiry"]
|
296
|
+
KeyN_1["KeyN: KeyN-1||""||Expiry"] --> KeyN
|
297
297
|
end
|
298
298
|
|
299
299
|
subgraph "Allocated Keys (Non-Shared Mode)"
|
@@ -1,15 +1,15 @@
|
|
1
1
|
redis_allocator/__init__.py,sha256=TVjUm-8YEu_MQD_PkfeIKiVknpCJBrUY9cWN1LlaZcU,1016
|
2
|
-
redis_allocator/_version.py,sha256=
|
3
|
-
redis_allocator/allocator.py,sha256=
|
2
|
+
redis_allocator/_version.py,sha256=2eiWQI55fd-roDdkt4Hvl9WzrTJ4xQo33VzFud6D03U,22
|
3
|
+
redis_allocator/allocator.py,sha256=Bo4Ck7mqg-Z8KdQH-iqeHfdEbyhMqBD0c2g5T3E5sBU,48730
|
4
4
|
redis_allocator/lock.py,sha256=fqf6WUWHKYenEArWopMIF6kWEnDfADC-bZvnQImsQVo,27400
|
5
5
|
redis_allocator/task_queue.py,sha256=8DjNr2uxhzCsHatV_CHOeGh7_K9pqQZFApSbe2blRO0,14989
|
6
|
-
redis_allocator-0.
|
6
|
+
redis_allocator-0.4.0.dist-info/licenses/LICENSE,sha256=Wt4X1rHpffQfEiyWcDUx8BMLjXxfPqaiYZ7Lgsj7L4c,1068
|
7
7
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
tests/conftest.py,sha256=
|
8
|
+
tests/conftest.py,sha256=Ts82uylQSzP_GcaN0E02o3xcFdjw20cXNzh3RAdYKW4,3967
|
9
9
|
tests/test_allocator.py,sha256=hFKgLe_yONtEjjm6zssUnhK0tzihG_1xZMziztHmqqA,22404
|
10
10
|
tests/test_lock.py,sha256=MDMRNN46VhWqkHUIhYOMEDgZkFFCW_WjwRLTOjkFF-Q,46952
|
11
11
|
tests/test_task_queue.py,sha256=Fh5naikFajfOvL6GngEy_TPfOYCYZolZfVwtR6T4dTY,31710
|
12
|
-
redis_allocator-0.
|
13
|
-
redis_allocator-0.
|
14
|
-
redis_allocator-0.
|
15
|
-
redis_allocator-0.
|
12
|
+
redis_allocator-0.4.0.dist-info/METADATA,sha256=rXeA3Nsb6eie8H5G10HXLlLI8jCRs45I1C06seN-Sgs,21727
|
13
|
+
redis_allocator-0.4.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
14
|
+
redis_allocator-0.4.0.dist-info/top_level.txt,sha256=0hXzU7sK5FCeSolTEYxThOt3HOybnwaXv1FLRJvHVgI,22
|
15
|
+
redis_allocator-0.4.0.dist-info/RECORD,,
|
tests/conftest.py
CHANGED
File without changes
|
File without changes
|
File without changes
|