# 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/bc/ae/bd696c8d712027d9d7e3970b681708521d9ab5d37f745003f140f594ff39/dgapplock-1.0.0a5.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.0a5",
"project_urls": null,
"split_keywords": [
"sqlalchemy",
" client",
" postgresql",
" mssql",
" oracle"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "13c1c495dd948222a2ab2c92d10c90503b13d9dfea4544f81ef32b4597905a1a",
"md5": "3394f5ccd34cd8c4eb16be71d1ecf630",
"sha256": "3d481cfee07ddd842932afba8dec98b12c69af8b68d7d06cb6c843709867eda9"
},
"downloads": -1,
"filename": "dgapplock-1.0.0a5-py3-none-any.whl",
"has_sig": false,
"md5_digest": "3394f5ccd34cd8c4eb16be71d1ecf630",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 6662,
"upload_time": "2025-08-20T09:09:22",
"upload_time_iso_8601": "2025-08-20T09:09:22.535572Z",
"url": "https://files.pythonhosted.org/packages/13/c1/c495dd948222a2ab2c92d10c90503b13d9dfea4544f81ef32b4597905a1a/dgapplock-1.0.0a5-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "bcaebd696c8d712027d9d7e3970b681708521d9ab5d37f745003f140f594ff39",
"md5": "b63d7be34191466e317dcc9562b33bdc",
"sha256": "529ec644b038ecc8eb3ef50e38fecabd3e60ac62b4c57e000f4230b7578d28bc"
},
"downloads": -1,
"filename": "dgapplock-1.0.0a5.tar.gz",
"has_sig": false,
"md5_digest": "b63d7be34191466e317dcc9562b33bdc",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 6124,
"upload_time": "2025-08-20T09:09:23",
"upload_time_iso_8601": "2025-08-20T09:09:23.714162Z",
"url": "https://files.pythonhosted.org/packages/bc/ae/bd696c8d712027d9d7e3970b681708521d9ab5d37f745003f140f594ff39/dgapplock-1.0.0a5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-20 09:09:23",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "dgapplock"
}