Last active
April 19, 2019 06:01
-
-
Save TylerHendrickson/1c7eac348076f6bf44e17568fe600f10 to your computer and use it in GitHub Desktop.
Distributed lock decorator backed by DynamoDB (or DLDBBDDB for short)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import functools | |
| import sys | |
| import time | |
| import boto3 | |
| import botocore | |
| from python_dynamodb_lock.python_dynamodb_lock import DynamoDBLockClient | |
| lock_client = DynamoDBLockClient(boto3.resource('dynamodb')) | |
| # This may be done in infra config (terraform, cloudformation, etc) instead: | |
| try: | |
| lock_client.create_dynamodb_table(boto3.client('dynamodb')) | |
| except botocore.exceptions.ClientError as e: | |
| if 'ResourceInUseException' not in str(e): | |
| raise | |
| else: | |
| print('DDB Table already exists') | |
| def distributed_lock(fn): | |
| """Decorator that waits until any other instances | |
| of the decorated function (in a distributed system) | |
| have finished executing before allowing local execution. | |
| """ | |
| key = f'{fn.__module__}.{fn.__qualname__}' | |
| @functools.wraps(fn) | |
| def wrapper(*args, **kwargs): | |
| with lock_client.acquire_lock(key): | |
| return fn(*args, **kwargs) | |
| return wrapper | |
| @distributed_lock | |
| def foo(seconds: int): | |
| """A function that must be executed in an exclusive manner, | |
| within a distributed system. | |
| This just sleeps. | |
| """ | |
| time.sleep(seconds) | |
| def main() -> int: | |
| """Runs the example, expecting a single positional int argument | |
| that defines the sleep duration. Program execution time will be at | |
| least slightly higher than this value, plus whatever time was spent | |
| waiting to acquire the lock. | |
| """ | |
| try: | |
| duration = int(sys.argv[1]) | |
| except (IndexError, ValueError): | |
| print('Bad/missing positional argument for duration!') | |
| return 1 | |
| start = time.time() | |
| foo(duration) | |
| runtime = time.time() - start | |
| print(f'foo({duration}) returned after {runtime} seconds') | |
| return 0 | |
| if __name__ == '__main__': | |
| sys.exit(main()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| boto3==1.9.133 | |
| python-dynamodb-lock==0.9.1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment