Allocator Module
This module provides resource allocation mechanisms using Redis as the backend.
RedisAllocator
- class redis_allocator.allocator.RedisAllocator[source]
A Redis-based distributed allocation system.
Manages a pool of resource identifiers (keys) using Redis, allowing distributed clients to allocate, free, and manage these resources. It leverages Redis’s atomic operations via Lua scripts for safe concurrent access.
The allocator maintains a doubly-linked list in a Redis hash to track available (free) resources. Allocated resources are tracked using standard Redis keys that act as locks.
Key Concepts: - Allocation Pool: A set of resource identifiers (keys) managed by the allocator.
Stored in a Redis hash (<prefix>|<suffix>|pool) representing a doubly-linked list. Head/Tail pointers are stored in separate keys (<prefix>|<suffix>|pool|head, <prefix>|<suffix>|pool|tail).
Free List: The subset of keys within the pool that are currently available. Represented by the linked list structure within the pool hash.
Allocated State: A key is considered allocated if a corresponding lock key exists (<prefix>|<suffix>:<key>).
Shared Mode: If shared=True, allocating a key moves it to the tail of the free list but does not create a lock key. This allows multiple clients to “allocate” the same key concurrently, effectively using the list as a rotating pool. If shared=False (default), allocation creates a lock key, granting exclusive access.
Soft Binding: Allows associating a logical name with an allocated key. If an object provides a name, the allocator tries to reuse the previously bound key for that name. Stored in Redis keys like <prefix>|<suffix>-cache:bind:<name>.
Garbage Collection (GC): Periodically scans the pool to reconcile the free list with the lock states. Removes expired/locked items from the free list and returns items whose locks have expired back to the free list.
Policies: Uses RedisAllocatorPolicy (e.g., DefaultRedisAllocatorPolicy) to customize allocation behavior, GC triggering, and pool updates.
Generic type U should implement RedisAllocatableClass.
- __init__(redis, prefix, suffix='allocator', eps=1e-06, shared=False, policy=None)[source]
Initializes the RedisAllocator.
- Parameters:
redis (Redis) – StrictRedis client instance (must decode responses).
prefix (str) – Prefix for all Redis keys used by this allocator instance.
suffix – Suffix to uniquely identify this allocator instance’s keys.
eps – Small float tolerance for comparisons (used by underlying lock).
shared – If True, operates in shared mode (keys are rotated, not locked). If False (default), keys are locked upon allocation.
policy (RedisAllocatorPolicy[U] | None) – Optional allocation policy. Defaults to DefaultRedisAllocatorPolicy.
- __contains__(key)[source]
Check if a resource identifier is in the allocation pool.
- Parameters:
key – Resource identifier to check
- Returns:
True if the resource is in the pool, False otherwise
- update_soft_bind(name, key, timeout=3600)[source]
Update a soft binding between a name and a resource.
Soft bindings create a persistent mapping between named objects and allocated keys, allowing the same key to be consistently allocated to the same named object. This is useful for maintaining affinity between objects and their resources.
- unbind_soft_bind(name)[source]
Remove a soft binding.
This removes the persistent mapping between a named object and its allocated key, allowing the key to be freely allocated to any requestor.
- Parameters:
name (str) – Name of the soft binding to remove
- malloc_key(timeout=120, name=None, cache_timeout=3600)[source]
Allocate a resource key from the pool.
The behavior depends on the allocator’s shared mode: - In non-shared mode (default): Locks the allocated key for exclusive access - In shared mode: Simply removes the key from the free list without locking it
- Parameters:
timeout (float | timedelta | None) – How long the allocation lock should be valid (in seconds).
name (str | None) – Optional name to use for soft binding.
cache_timeout (float | timedelta | None) – Timeout for the soft binding cache entry (seconds). Defaults to 3600. If <= 0, cache entry persists indefinitely.
- Returns:
Resource identifier if allocation was successful, None otherwise
- Return type:
str | None
- malloc(timeout=120, obj=None, params=None, cache_timeout=3600)[source]
Allocate a resource from the pool and wrap it in a RedisAllocatorObject.
If a policy is configured, it will be used to control the allocation behavior. Otherwise, the basic allocation mechanism will be used.
- Parameters:
timeout (float | timedelta | None) – How long the allocation lock should be valid (in seconds)
obj (U | None) – The object to wrap in the RedisAllocatorObject. If it has a .name, soft binding will be attempted.
params (dict | None) – Additional parameters to associate with the allocated object.
cache_timeout (float | timedelta | None) – Timeout for the soft binding cache entry (seconds). Defaults to 3600. Passed to the policy or malloc_key.
- Returns:
RedisAllocatorObject wrapping the allocated resource if successful, None otherwise
- Return type:
RedisAllocatorObject[U] | None
- free(obj, timeout=-1)[source]
Free an allocated object.
- Parameters:
obj (RedisAllocatorObject[U]) – The allocated object to free
timeout (int) – Optional timeout in seconds for the pool item (-1 means no timeout)
- __iter__()
Iterate over the keys in the pool.
- __len__()
Get the number of keys in the pool.
- deleq(key, value)
Deletes a key when the comparison value is equal to the current value.
- delge(key, value)
Deletes a key when the comparison value is greater than or equal to the current value.
- delgt(key, value)
Deletes a key when the comparison value is greater than the current value.
- delle(key, value)
Deletes a key when the comparison value is less than or equal to the current value.
- dellt(key, value)
Deletes a key when the comparison value is less than the current value.
- delne(key, value)
Deletes a key when the comparison value is not equal to the current value.
- health_check()
Check the health status of the keys in the pool.
- is_locked(key)
Check if a key is locked.
- items_locked_status()
Get (key, lock_status) pairs for all keys in the pool.
- key_status(key, timeout=120)
Get the status of a key.
- Parameters:
- Returns:
The current status of the key.
- Return type:
- lock(key, value='1', timeout=120)
Try to lock a key for a specified duration.
- lock_value(key)
Get the value of a locked key.
- rlock(key, value='1', timeout=120)
Try to lock a key for a specified duration.
When the value is the same as the current value, the function will return True.
- seteq(key, value, set_value=None, ex=None)
Sets a new value when the comparison value is equal to the current value.
- setge(key, value, set_value=None, ex=None)
Sets a new value when the comparison value is greater than or equal to the current value.
- setgt(key, value, set_value=None, ex=None)
Sets a new value when the comparison value is greater than the current value.
- setle(key, value, set_value=None, ex=None)
Sets a new value when the comparison value is less than or equal to the current value.
- setlt(key, value, set_value=None, ex=None)
Sets a new value when the comparison value is less than the current value.
- setne(key, value, set_value=None, ex=None)
Sets a new value when the comparison value is not equal to the current value.
- unlock(key)
Forcefully release a key without checking if the key is locked.
- update(key, value='1', timeout=120)
Lock a key for a specified duration without checking if the key is already locked.
RedisAllocatorObject
RedisAllocatableClass
- class redis_allocator.allocator.RedisAllocatableClass[source]
A class that can be allocated through RedisAllocator.
You should inherit from this class and implement the set_config method.
RedisThreadHealthCheckPool
- class redis_allocator.allocator.RedisThreadHealthCheckPool[source]
A class that provides a simple interface for managing the health status of a thread.
This class enables tracking the health status of threads in a distributed environment using Redis locks.
Allocator
Redis-based distributed memory allocation system.
This module provides the core functionality of the RedisAllocator system, allowing for distributed memory allocation with support for garbage collection, thread health checking, and priority-based allocation mechanisms.
Key features: 1. Shared vs non-shared allocation modes:
In shared mode, allocating an item simply removes it from the free list and puts it back to the tail
In non-shared mode, allocation locks the item to prevent others from accessing it
Garbage collection for stale/unhealthy items: - Items that are locked (unhealthy) but in the free list are removed - Items that are not in the free list but haven’t been updated within their timeout are freed
Soft binding mechanism: - Maps object names to allocated keys for consistent allocation - Prioritizes previously allocated keys when the same named object requests allocation
Support for an updater to refresh the pool’s keys periodically
Policy-based control of allocation behavior through RedisAllocatorPolicy
- class redis_allocator.allocator.RedisThreadHealthCheckPool[source]
Bases:
RedisLockPool
A class that provides a simple interface for managing the health status of a thread.
This class enables tracking the health status of threads in a distributed environment using Redis locks.
- class redis_allocator.allocator.RedisAllocatableClass[source]
Bases:
ABC
A class that can be allocated through RedisAllocator.
You should inherit from this class and implement the set_config method.
- class redis_allocator.allocator.RedisAllocatorObject[source]
Bases:
Generic
[U
]Represents an object allocated through RedisAllocator.
This class provides an interface for working with allocated objects including locking and unlocking mechanisms for thread-safe operations.
- __init__(allocator, key, obj=None, params=None)[source]
Initialize a RedisAllocatorObject instance.
- Parameters:
allocator (RedisAllocator) – The RedisAllocator that created this object
key (str) – The Redis key for this allocated object
obj (U | None) – The actual object being allocated
params (dict | None) – Additional parameters passed by local program
- allocator: RedisAllocator
- class redis_allocator.allocator.RedisAllocatorUpdater[source]
Bases:
object
A class that updates the allocator keys.
- class redis_allocator.allocator.RedisAllocatorPolicy[source]
-
Abstract base class for Redis allocator policies.
This class defines the interface for allocation policies that can be used with RedisAllocator to control allocation behavior.
- initialize(allocator)[source]
Initialize the policy with an allocator instance.
- Parameters:
allocator (RedisAllocator[U]) – The RedisAllocator instance to use with this policy
- abstract malloc(allocator, timeout=120, obj=None, params=None, cache_timeout=3600)[source]
Allocate a resource according to the policy.
- Parameters:
allocator (RedisAllocator[U]) – The RedisAllocator instance
timeout (float | timedelta | None) – How long the allocation should be valid (in seconds)
obj (U | None) – The object to associate with the allocation
params (dict | None) – Additional parameters for the allocation
cache_timeout (float | timedelta | None) – Timeout for the soft binding cache entry (seconds). Defaults to 3600.
- Returns:
RedisAllocatorObject if allocation was successful, None otherwise
- Return type:
RedisAllocatorObject[U] | None
- abstract refresh_pool(allocator)[source]
Refresh the allocation pool.
This method is called periodically to update the pool with new resources.
- Parameters:
allocator (RedisAllocator[U]) – The RedisAllocator instance
- abstract refresh_pool_all(allocator)[source]
Refresh the allocation pool.
- Parameters:
allocator (RedisAllocator[U])
- check_health_once(r_obj, duration=3600)[source]
Check the health of the object.
- Parameters:
r_obj (RedisAllocatorObject[U])
duration (int)
- Return type:
- class redis_allocator.allocator.DefaultRedisAllocatorPolicy[source]
Bases:
RedisAllocatorPolicy
[U
]Default implementation of RedisAllocatorPolicy.
This policy provides the following features: 1. Garbage collection before allocation: Automatically performs garbage collection
operations before allocating resources to ensure stale resources are reclaimed.
Soft binding prioritization: Prioritizes allocation of previously bound keys for named objects, creating a consistent mapping between object names and keys. If a soft binding exists but the bound key is no longer in the pool, the binding is ignored and a new key is allocated.
Periodic pool updates: Uses an optional updater to refresh the pool’s keys at configurable intervals. Only one process/thread (the one that acquires the update lock) will perform the update.
Configurable expiry times: Allows setting default expiry durations for pool items, ensuring automatic cleanup of stale resources even without explicit garbage collection.
The policy controls when garbage collection happens, when the pool is refreshed with new keys, and how allocation prioritizes resources.
- __init__(gc_count=5, update_interval=300, expiry_duration=-1, updater=None, auto_close=False)[source]
Initialize the default allocation policy.
- Parameters:
gc_count (int) – Number of GC operations to perform before allocation
update_interval (int) – Interval in seconds between pool updates
expiry_duration (int) – Default timeout for pool items (-1 means no timeout)
updater (RedisAllocatorUpdater | None) – Optional updater for refreshing the pool’s keys
auto_close (bool) – If True, the allocator will automatically close the object when it is not unique
- initialize(allocator)[source]
Initialize the policy with an allocator instance.
- Parameters:
allocator (RedisAllocator[U]) – The RedisAllocator instance to use with this policy
- refresh_pool_all(allocator)[source]
Refresh the allocation pool.
- Parameters:
allocator (RedisAllocator[U])
- malloc(allocator, timeout=120, obj=None, params=None, cache_timeout=3600)[source]
Allocate a resource according to the policy.
This implementation: 1. Performs GC operations before allocation 2. Checks for soft binding based on object name 3. Falls back to regular allocation if no soft binding exists
- Parameters:
allocator (RedisAllocator[U]) – The RedisAllocator instance
timeout (float | timedelta | None) – How long the allocation should be valid (in seconds)
obj (U | None) – The object to associate with the allocation
params (dict | None) – Additional parameters for the allocation
cache_timeout (float | timedelta | None) – Timeout for the soft binding cache entry (seconds). Defaults to 3600.
- Returns:
RedisAllocatorObject if allocation was successful, None otherwise
- Return type:
RedisAllocatorObject[U] | None
- refresh_pool(allocator, shuffle=True, n=1)[source]
Refresh the allocation pool using the updater.
- Parameters:
allocator (RedisAllocator[U]) – The RedisAllocator instance
- finalize(allocator)[source]
Finalize the policy.
- Parameters:
allocator (RedisAllocator[U])
- class redis_allocator.allocator.RedisAllocator[source]
Bases:
RedisLockPool
,Generic
[U
]A Redis-based distributed allocation system.
Manages a pool of resource identifiers (keys) using Redis, allowing distributed clients to allocate, free, and manage these resources. It leverages Redis’s atomic operations via Lua scripts for safe concurrent access.
The allocator maintains a doubly-linked list in a Redis hash to track available (free) resources. Allocated resources are tracked using standard Redis keys that act as locks.
Key Concepts: - Allocation Pool: A set of resource identifiers (keys) managed by the allocator.
Stored in a Redis hash (<prefix>|<suffix>|pool) representing a doubly-linked list. Head/Tail pointers are stored in separate keys (<prefix>|<suffix>|pool|head, <prefix>|<suffix>|pool|tail).
Free List: The subset of keys within the pool that are currently available. Represented by the linked list structure within the pool hash.
Allocated State: A key is considered allocated if a corresponding lock key exists (<prefix>|<suffix>:<key>).
Shared Mode: If shared=True, allocating a key moves it to the tail of the free list but does not create a lock key. This allows multiple clients to “allocate” the same key concurrently, effectively using the list as a rotating pool. If shared=False (default), allocation creates a lock key, granting exclusive access.
Soft Binding: Allows associating a logical name with an allocated key. If an object provides a name, the allocator tries to reuse the previously bound key for that name. Stored in Redis keys like <prefix>|<suffix>-cache:bind:<name>.
Garbage Collection (GC): Periodically scans the pool to reconcile the free list with the lock states. Removes expired/locked items from the free list and returns items whose locks have expired back to the free list.
Policies: Uses RedisAllocatorPolicy (e.g., DefaultRedisAllocatorPolicy) to customize allocation behavior, GC triggering, and pool updates.
Generic type U should implement RedisAllocatableClass.
- __init__(redis, prefix, suffix='allocator', eps=1e-06, shared=False, policy=None)[source]
Initializes the RedisAllocator.
- Parameters:
redis (Redis) – StrictRedis client instance (must decode responses).
prefix (str) – Prefix for all Redis keys used by this allocator instance.
suffix – Suffix to uniquely identify this allocator instance’s keys.
eps – Small float tolerance for comparisons (used by underlying lock).
shared – If True, operates in shared mode (keys are rotated, not locked). If False (default), keys are locked upon allocation.
policy (RedisAllocatorPolicy[U] | None) – Optional allocation policy. Defaults to DefaultRedisAllocatorPolicy.
- __contains__(key)[source]
Check if a resource identifier is in the allocation pool.
- Parameters:
key – Resource identifier to check
- Returns:
True if the resource is in the pool, False otherwise
- update_soft_bind(name, key, timeout=3600)[source]
Update a soft binding between a name and a resource.
Soft bindings create a persistent mapping between named objects and allocated keys, allowing the same key to be consistently allocated to the same named object. This is useful for maintaining affinity between objects and their resources.
- unbind_soft_bind(name)[source]
Remove a soft binding.
This removes the persistent mapping between a named object and its allocated key, allowing the key to be freely allocated to any requestor.
- Parameters:
name (str) – Name of the soft binding to remove
- malloc_key(timeout=120, name=None, cache_timeout=3600)[source]
Allocate a resource key from the pool.
The behavior depends on the allocator’s shared mode: - In non-shared mode (default): Locks the allocated key for exclusive access - In shared mode: Simply removes the key from the free list without locking it
- Parameters:
timeout (float | timedelta | None) – How long the allocation lock should be valid (in seconds).
name (str | None) – Optional name to use for soft binding.
cache_timeout (float | timedelta | None) – Timeout for the soft binding cache entry (seconds). Defaults to 3600. If <= 0, cache entry persists indefinitely.
- Returns:
Resource identifier if allocation was successful, None otherwise
- Return type:
str | None
- malloc(timeout=120, obj=None, params=None, cache_timeout=3600)[source]
Allocate a resource from the pool and wrap it in a RedisAllocatorObject.
If a policy is configured, it will be used to control the allocation behavior. Otherwise, the basic allocation mechanism will be used.
- Parameters:
timeout (float | timedelta | None) – How long the allocation lock should be valid (in seconds)
obj (U | None) – The object to wrap in the RedisAllocatorObject. If it has a .name, soft binding will be attempted.
params (dict | None) – Additional parameters to associate with the allocated object.
cache_timeout (float | timedelta | None) – Timeout for the soft binding cache entry (seconds). Defaults to 3600. Passed to the policy or malloc_key.
- Returns:
RedisAllocatorObject wrapping the allocated resource if successful, None otherwise
- Return type:
RedisAllocatorObject[U] | None
- free(obj, timeout=-1)[source]
Free an allocated object.
- Parameters:
obj (RedisAllocatorObject[U]) – The allocated object to free
timeout (int) – Optional timeout in seconds for the pool item (-1 means no timeout)
Core Concepts & Visualization
Allocator Pool Structure (Conceptual)
The allocator manages a pool of resources using several Redis keys:
Pool Hash (`<prefix>|<suffix>|pool`): Stores the resource keys currently in the pool. The value for each key represents its position in a doubly-linked list used for the free list (e.g., prev_key||next_key||expiry_timestamp). A special value (#ALLOCATED) indicates the key is part of the pool but not currently free.
Head Pointer (`…|pool|head`): A simple key holding the resource key currently at the head of the free list.
Tail Pointer (`…|pool|tail`): A simple key holding the resource key currently at the tail of the free list.
Lock Keys (`<prefix>|<suffix>:<key>`): Standard Redis keys used as locks in non-shared mode. Their existence indicates a resource is allocated.
Soft Bind Cache Keys (`<prefix>|<suffix>-cache:bind:<name>`): Store the mapping between a logical name and an allocated resource key for soft binding.
graph TD subgraph Redis Keys HKey["<prefix>|<suffix>|pool|head"] --> Key1["Key1: ""||Key2||Expiry"] TKey["<prefix>|<suffix>|pool|tail"] --> KeyN["KeyN: KeyN-1||""||Expiry"] PoolHash["<prefix>|<suffix>|pool (Hash)"] end subgraph "PoolHash Contents (Doubly-Linked Free List)" Key1 --> Key2["Key2: Key1||Key3||Expiry"] Key2 --> Key3["Key3: Key2||...||Expiry"] Key3 --> ... KeyN_1[...] --> KeyN end subgraph "Allocated Keys (Non-Shared Mode)" LKey1["<prefix>|<suffix>:AllocatedKey1"] LKeyX["<prefix>|<suffix>:AllocatedKeyX"] end subgraph "Soft Bind Cache" CacheKey1["<prefix>|<suffix>-cache:bind:name1"] --> LKey1 end