# AppLocker - Distributed Application Lock Manager


## Overview
AppLocker is a Python library that provides distributed application locking using Redis. It ensures that only one instance of your application can run a critical section of code at a time, even across multiple servers.
Key features:
- **Distributed locking** across multiple application instances
- **Automatic lock renewal** (heartbeat) to prevent premature expiration
- **Lock ownership verification** to prevent accidental release
- **Context manager support** for easy use in `with` statements
- **Stale lock detection** and recovery
## Installation
```bash
pip install your-package-name
```
## Prerequisites
- Python 3.8+
- Redis server
- `dglog` and `dgredis` packages (will be installed automatically if using pip)
## Quick Start
```python
from app_locker import AppLocker
# Configure Redis connection
redis_config = {
"host": "localhost",
"port": 6379,
# Add other Redis parameters as needed
}
# Create a locker instance
locker = AppLocker(redis_config, "my_application")
# Usage example
with locker:
print("This code is protected by a distributed lock")
# Only one instance of your application can execute this at a time
```
## Configuration
### Basic Configuration
When creating an `AppLocker` instance, you need to provide:
1. Redis configuration dictionary (host, port, etc.)
2. Your application name (used as part of the lock key)
3. Optional parameters:
- `ttl`: Lock time-to-live in seconds (default: 60)
- `logger_`: Custom logger instance
### Advanced Configuration
You can customize the lock behavior by:
1. Setting a specific lock key instead of the default `QUEUE:{application}`
2. Adjusting the stale timeout for force-release operations
3. Providing a custom logger for tracking lock operations
## Usage Examples
### Basic Locking
```python
if locker.acquire():
try:
# Critical section
print("Doing important work")
finally:
locker.release()
else:
print("Could not acquire lock - another instance is running")
```
### Context Manager
```python
with locker.acquired():
# Critical section
print("This code is protected")
```
### Checking Lock Status
```python
if locker.is_my_lock():
print("We currently hold the lock")
lock_info = locker.get_lock_info()
if lock_info:
print(f"Lock held by {lock_info['owner']} since {lock_info['acquired_at']}")
```
### Force Release Stale Lock
```python
if locker.force_release_if_stale(stale_timeout=120):
print("Released a stale lock")
```
## Best Practices
1. **Keep TTL reasonable** - Set it long enough for your operations but not too long (default 60s is good for most cases)
2. **Always use context managers** when possible for safer lock handling
3. **Check lock ownership** before performing sensitive operations
4. **Monitor lock duration** using `get_lock_duration()` to optimize your TTL
5. **Handle lock acquisition failures** gracefully in your application
## Troubleshooting
### Common Issues
1. **Can't acquire lock**
- Check if another instance is running
- Verify Redis connection
- Check if a stale lock needs to be force-released
2. **Unexpected lock release**
- Ensure your operations complete within the TTL
- Check for network issues with Redis
3. **Permission errors**
- Verify Redis credentials in your configuration
### Logging
AppLocker provides detailed logging about lock operations. If you're not seeing logs:
- Make sure logging is configured properly
- Pass a custom logger to the constructor if needed
## API Reference
See the full [API documentation](API.md) for detailed information about all available methods and parameters.
## License
[MIT License](LICENSE)
Raw data
{
"_id": null,
"home_page": null,
"name": "dgapplock",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "sqlalchemy, client, postgresql, mssql, oracle",
"author": "r.rasputin",
"author_email": "r.rasputin@s7.ru",
"download_url": "https://files.pythonhosted.org/packages/b6/fe/cc69695d8ac4b8801b881fbf054f4da2dce0b6d38ecfc0f6cee901313f28/dgapplock-1.0.0a1.tar.gz",
"platform": null,
"description": "# AppLocker - Distributed Application Lock Manager\n\n\n\n\n## Overview\n\nAppLocker is a Python library that provides distributed application locking using Redis. It ensures that only one instance of your application can run a critical section of code at a time, even across multiple servers.\n\nKey features:\n- **Distributed locking** across multiple application instances\n- **Automatic lock renewal** (heartbeat) to prevent premature expiration\n- **Lock ownership verification** to prevent accidental release\n- **Context manager support** for easy use in `with` statements\n- **Stale lock detection** and recovery\n\n## Installation\n\n```bash\npip install your-package-name\n```\n\n## Prerequisites\n\n- Python 3.8+\n- Redis server\n- `dglog` and `dgredis` packages (will be installed automatically if using pip)\n\n## Quick Start\n\n```python\nfrom app_locker import AppLocker\n\n# Configure Redis connection\nredis_config = {\n \"host\": \"localhost\",\n \"port\": 6379,\n # Add other Redis parameters as needed\n}\n\n# Create a locker instance\nlocker = AppLocker(redis_config, \"my_application\")\n\n# Usage example\nwith locker:\n print(\"This code is protected by a distributed lock\")\n # Only one instance of your application can execute this at a time\n```\n\n## Configuration\n\n### Basic Configuration\n\nWhen creating an `AppLocker` instance, you need to provide:\n\n1. Redis configuration dictionary (host, port, etc.)\n2. Your application name (used as part of the lock key)\n3. Optional parameters:\n - `ttl`: Lock time-to-live in seconds (default: 60)\n - `logger_`: Custom logger instance\n\n### Advanced Configuration\n\nYou can customize the lock behavior by:\n\n1. Setting a specific lock key instead of the default `QUEUE:{application}`\n2. Adjusting the stale timeout for force-release operations\n3. Providing a custom logger for tracking lock operations\n\n## Usage Examples\n\n### Basic Locking\n\n```python\nif locker.acquire():\n try:\n # Critical section\n print(\"Doing important work\")\n finally:\n locker.release()\nelse:\n print(\"Could not acquire lock - another instance is running\")\n```\n\n### Context Manager\n\n```python\nwith locker.acquired():\n # Critical section\n print(\"This code is protected\")\n```\n\n### Checking Lock Status\n\n```python\nif locker.is_my_lock():\n print(\"We currently hold the lock\")\n \nlock_info = locker.get_lock_info()\nif lock_info:\n print(f\"Lock held by {lock_info['owner']} since {lock_info['acquired_at']}\")\n```\n\n### Force Release Stale Lock\n\n```python\nif locker.force_release_if_stale(stale_timeout=120):\n print(\"Released a stale lock\")\n```\n\n## Best Practices\n\n1. **Keep TTL reasonable** - Set it long enough for your operations but not too long (default 60s is good for most cases)\n2. **Always use context managers** when possible for safer lock handling\n3. **Check lock ownership** before performing sensitive operations\n4. **Monitor lock duration** using `get_lock_duration()` to optimize your TTL\n5. **Handle lock acquisition failures** gracefully in your application\n\n## Troubleshooting\n\n### Common Issues\n\n1. **Can't acquire lock**\n - Check if another instance is running\n - Verify Redis connection\n - Check if a stale lock needs to be force-released\n\n2. **Unexpected lock release**\n - Ensure your operations complete within the TTL\n - Check for network issues with Redis\n\n3. **Permission errors**\n - Verify Redis credentials in your configuration\n\n### Logging\n\nAppLocker provides detailed logging about lock operations. If you're not seeing logs:\n- Make sure logging is configured properly\n- Pass a custom logger to the constructor if needed\n\n## API Reference\n\nSee the full [API documentation](API.md) for detailed information about all available methods and parameters.\n\n## License\n\n[MIT License](LICENSE)\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "AppLocker",
"version": "1.0.0a1",
"project_urls": null,
"split_keywords": [
"sqlalchemy",
" client",
" postgresql",
" mssql",
" oracle"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "79c09b7bb80df4673106798363689fa006755389dbb665e1669943a80097d7a4",
"md5": "0e76b14ea25aa5430b922d564b98e65c",
"sha256": "176732996c28d036b70d41551e41566b8ba4fc9e084e8f4ceacd07e4896422c6"
},
"downloads": -1,
"filename": "dgapplock-1.0.0a1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "0e76b14ea25aa5430b922d564b98e65c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 6157,
"upload_time": "2025-07-17T11:26:12",
"upload_time_iso_8601": "2025-07-17T11:26:12.547051Z",
"url": "https://files.pythonhosted.org/packages/79/c0/9b7bb80df4673106798363689fa006755389dbb665e1669943a80097d7a4/dgapplock-1.0.0a1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "b6fecc69695d8ac4b8801b881fbf054f4da2dce0b6d38ecfc0f6cee901313f28",
"md5": "f5d78835de7f55df0ae87b446e774d53",
"sha256": "802033ab7202160ceec1fd314c7c54c57f536dc1a7f5ada1878a6526f1ca889d"
},
"downloads": -1,
"filename": "dgapplock-1.0.0a1.tar.gz",
"has_sig": false,
"md5_digest": "f5d78835de7f55df0ae87b446e774d53",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 5623,
"upload_time": "2025-07-17T11:26:14",
"upload_time_iso_8601": "2025-07-17T11:26:14.024329Z",
"url": "https://files.pythonhosted.org/packages/b6/fe/cc69695d8ac4b8801b881fbf054f4da2dce0b6d38ecfc0f6cee901313f28/dgapplock-1.0.0a1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-17 11:26:14",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "dgapplock"
}