Quick and small memcached client for Python
86
Complete exception hierarchy for robust error handling, covering connection issues, protocol errors, and operational failures. pylibmc provides specific exception types to help applications handle different error conditions appropriately.
Foundation exception classes that form the hierarchy for all pylibmc errors.
class Error(Exception):
"""
Base exception for all pylibmc errors.
All other pylibmc exceptions inherit from this class.
"""
class MemcachedError(Error):
"""
Backwards compatible alias for Error.
Maintained for compatibility with older versions.
"""
class CacheMiss(Error):
"""
Raised when a requested key is not found in the cache.
This is a normal condition, not necessarily an error.
"""Exceptions related to network connectivity and server communication.
class ConnectionError(Error):
"""
General connection failure to memcached server.
Raised when client cannot establish or maintain connection.
"""
class ConnectionBindError(Error):
"""
Failed to bind connection to specific address.
Usually indicates network configuration issues.
"""
class HostLookupError(Error):
"""
DNS resolution failed for memcached server hostname.
Check hostname spelling and DNS configuration.
"""
class SocketCreateError(Error):
"""
Failed to create network socket for connection.
May indicate system resource limits or permissions.
"""
class UnixSocketError(Error):
"""
Error specific to Unix domain socket connections.
Check socket file permissions and path.
"""Exceptions related to memcached protocol communication and data format issues.
class ProtocolError(Error):
"""
Memcached protocol violation or unexpected response.
Usually indicates server or network issues.
"""
class WriteError(Error):
"""
Failed to write data to memcached server.
May indicate network issues or server problems.
"""
class ReadError(Error):
"""
Failed to read data from memcached server.
May indicate network timeout or connection issues.
"""
class UnknownReadFailure(Error):
"""
Unexpected failure during read operation.
Generic read error when specific cause is unknown.
"""Exceptions originating from memcached server responses and conditions.
class ServerError(Error):
"""
Internal server error reported by memcached.
Usually indicates server-side issues or bugs.
"""
class ClientError(Error):
"""
Client request error as reported by memcached server.
Indicates malformed request or invalid operation.
"""
class ServerDead(Error):
"""
Server is marked as dead due to repeated failures.
Server will be retried after retry_timeout period.
"""
class ServerDown(Error):
"""
Server is currently down or unreachable.
Temporary condition that may resolve automatically.
"""
class NoServers(Error):
"""
No servers are available for operations.
All servers may be down or configuration is empty.
"""Exceptions related to data operations, key validation, and value constraints.
class DataExists(Error):
"""
Data already exists when using add operation.
Normal condition when key already present for add().
"""
class DataDoesNotExist(Error):
"""
Data does not exist for replace or update operation.
Normal condition when key missing for replace().
"""
class NotFound(Error):
"""
Requested key was not found in cache.
Similar to CacheMiss but used in different contexts.
"""
class BadKeyProvided(Error):
"""
Invalid key format or characters provided.
Key may contain invalid characters or be too long.
"""
class TooBig(Error):
"""
Value exceeds maximum size limit for memcached.
Default limit is 1MB, configurable on server.
"""Exceptions related to operation state and resource management.
class Failure(Error):
"""
General operation failure without specific cause.
Generic error when operation cannot complete.
"""
class AllocationError(Error):
"""
Memory allocation failure within pylibmc or libmemcached.
May indicate system memory pressure.
"""
class SomeErrors(Error):
"""
Some operations in batch failed while others succeeded.
Used with multi-key operations for partial failures.
"""
class FetchNotFinished(Error):
"""
Attempt to access results before fetch operation completed.
Usually indicates improper async operation handling.
"""
class NotSupportedError(Error):
"""
Requested operation is not supported by server or configuration.
Feature may require specific server version or compile options.
"""
class InvalidHostProtocolError(Error):
"""
Invalid protocol specified in server host specification.
Check server URL format and protocol specification.
"""
class UnknownStatKey(Error):
"""
Requested statistics key is not recognized by server.
Use get_stats() without arguments to see available keys.
"""Access to complete exception catalog and metadata.
errors: tuple # Tuple of all exception classes
exceptions: list # List of (name, exception_class) tuplesimport pylibmc
client = pylibmc.Client(["localhost:11211"])
try:
value = client.get("nonexistent_key")
if value is None:
print("Key not found")
except pylibmc.CacheMiss:
print("Cache miss - key doesn't exist")
except pylibmc.ConnectionError:
print("Cannot connect to memcached server")
except pylibmc.Error as e:
print(f"Memcached error: {e}")import pylibmc
import logging
logger = logging.getLogger(__name__)
def safe_cache_get(client, key, default=None):
"""Safely get value from cache with comprehensive error handling."""
try:
return client.get(key)
except pylibmc.CacheMiss:
logger.debug(f"Cache miss for key: {key}")
return default
except pylibmc.ConnectionError as e:
logger.error(f"Connection failed: {e}")
return default
except pylibmc.ServerError as e:
logger.error(f"Server error: {e}")
return default
except pylibmc.BadKeyProvided as e:
logger.warning(f"Invalid key format: {key} - {e}")
return default
except pylibmc.Error as e:
logger.exception(f"Unexpected cache error: {e}")
return default
def safe_cache_set(client, key, value, time=0):
"""Safely set value in cache with error handling."""
try:
return client.set(key, value, time)
except pylibmc.TooBig as e:
logger.warning(f"Value too large for key {key}: {e}")
return False
except pylibmc.BadKeyProvided as e:
logger.warning(f"Invalid key format: {key} - {e}")
return False
except pylibmc.ConnectionError as e:
logger.error(f"Connection failed during set: {e}")
return False
except pylibmc.ServerError as e:
logger.error(f"Server error during set: {e}")
return False
except pylibmc.Error as e:
logger.exception(f"Unexpected error during set: {e}")
return Falseimport pylibmc
client = pylibmc.Client(["localhost:11211"])
def safe_multi_get(client, keys):
"""Get multiple keys with proper error handling."""
try:
return client.get_multi(keys)
except pylibmc.SomeErrors as e:
logger.warning(f"Some keys failed in multi-get: {e}")
# Partial results may still be available
return {}
except pylibmc.NoServers as e:
logger.error(f"No servers available: {e}")
return {}
except pylibmc.Error as e:
logger.exception(f"Multi-get failed: {e}")
return {}
def safe_multi_set(client, key_value_pairs):
"""Set multiple keys with error handling."""
try:
failed_keys = client.set_multi(key_value_pairs)
if failed_keys:
logger.warning(f"Failed to set keys: {failed_keys}")
return failed_keys
except pylibmc.SomeErrors as e:
logger.warning(f"Partial failure in multi-set: {e}")
return list(key_value_pairs.keys()) # Assume all failed
except pylibmc.Error as e:
logger.exception(f"Multi-set failed completely: {e}")
return list(key_value_pairs.keys())import pylibmc
from queue import Empty
client = pylibmc.Client(["localhost:11211"])
pool = pylibmc.ClientPool()
pool.fill(client, 5)
def safe_pooled_operation(key, value=None):
"""Perform cache operation using pool with error handling."""
try:
with pool.reserve(block=False) as pooled_client:
if value is not None:
return pooled_client.set(key, value)
else:
return pooled_client.get(key)
except Empty:
logger.warning("Connection pool exhausted")
return None
except pylibmc.ConnectionError as e:
logger.error(f"Connection error in pool: {e}")
return None
except pylibmc.Error as e:
logger.exception(f"Cache error in pool: {e}")
return Noneimport pylibmc
import time
def create_resilient_client():
"""Create client configured for automatic failure recovery."""
client = pylibmc.Client([
"server1:11211",
"server2:11211",
"server3:11211"
], binary=True)
# Configure for automatic failover
client.behaviors = {
"auto_eject": True, # Remove failed servers
"failure_limit": 2, # Failures before ejection
"retry_timeout": 30, # Retry failed servers after 30s
"connect_timeout": 2000, # Quick connection timeout
}
return client
def resilient_operation(client, operation_func, max_retries=3):
"""Perform operation with retry logic for server failures."""
for attempt in range(max_retries):
try:
return operation_func()
except (pylibmc.ServerDead, pylibmc.ServerDown, pylibmc.NoServers) as e:
if attempt == max_retries - 1:
logger.error(f"All retry attempts failed: {e}")
raise
logger.warning(f"Server failure (attempt {attempt + 1}): {e}")
time.sleep(2 ** attempt) # Exponential backoff
except pylibmc.ConnectionError as e:
if attempt == max_retries - 1:
logger.error(f"Connection failed after retries: {e}")
raise
logger.warning(f"Connection error (attempt {attempt + 1}): {e}")
time.sleep(1)
# Usage
client = create_resilient_client()
def get_user_data(user_id):
return client.get(f"user:{user_id}")
try:
user_data = resilient_operation(client, lambda: get_user_data(123))
except pylibmc.Error:
# Fallback to database or default value
user_data = Noneimport pylibmc
from collections import defaultdict, Counter
class CacheErrorTracker:
"""Track and analyze cache error patterns."""
def __init__(self):
self.error_counts = Counter()
self.error_details = defaultdict(list)
def record_error(self, operation, error):
"""Record an error for analysis."""
error_type = type(error).__name__
self.error_counts[error_type] += 1
self.error_details[error_type].append({
'operation': operation,
'message': str(error),
'timestamp': time.time()
})
def get_stats(self):
"""Get error statistics."""
return dict(self.error_counts)
def should_fallback(self, error_threshold=10):
"""Determine if error rate suggests fallback needed."""
connection_errors = (
self.error_counts.get('ConnectionError', 0) +
self.error_counts.get('ServerDead', 0) +
self.error_counts.get('NoServers', 0)
)
return connection_errors >= error_threshold
# Usage
tracker = CacheErrorTracker()
client = pylibmc.Client(["localhost:11211"])
def monitored_cache_get(key):
"""Cache get with error monitoring."""
try:
return client.get(key)
except pylibmc.Error as e:
tracker.record_error('get', e)
if tracker.should_fallback():
logger.warning("High error rate - consider fallback strategy")
raiseInstall with Tessl CLI
npx tessl i tessl/pypi-pylibmcevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10