Skip to content

Commit 2d0a539

Browse files
author
Mohan Kishore
committed
Testing the docscript
1 parent 10a14db commit 2d0a539

5 files changed

Lines changed: 205 additions & 17 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,7 @@ ENV/
100100

101101
# mypy
102102
.mypy_cache/
103+
104+
# IDE(s)
105+
.idea/
106+
*.iml

.travis.yml

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,17 @@
1-
# Config file for automatic testing at travis-ci.org
2-
31
language: python
42
python:
5-
- 3.6
6-
- 3.5
7-
- 3.4
8-
- 2.7
9-
10-
# Command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors
3+
- 3.6
4+
- 3.5
5+
- 3.4
6+
- 2.7
117
install: pip install -U tox-travis
12-
13-
# Command to run tests, e.g. python setup.py test
148
script: tox
15-
16-
# Assuming you have installed the travis-ci CLI tool, after you
17-
# create the Github repo and add it to Travis, run the
18-
# following command to finish PyPI deployment setup:
19-
# $ travis encrypt --add deploy.password
209
deploy:
2110
provider: pypi
2211
distributions: sdist bdist_wheel
2312
user: mohankishore
2413
password:
25-
secure: PLEASE_REPLACE_ME
14+
secure: TMO3Szq5Z/hu+CM3q6VKbvJOkWWAznBgjYv5w05qwTkvLMNsWcSBlwumlJ4erA6Pzd408aKVmGN/mie1xDAutrhoWTf3i49NAY++BhkEfYuMZ5s3+LgUXr6l4+Gk4G9t92bc7nMgZIyk1irFr3z3b9NtyTtjPMcZv+pMs/wjjzLDfeWr1rkZ0MiDx/0jUu1AWmkBH7MDWjlFipAT/ST3SjVqrmUyGeDNzQ2bKBLtSp64Cmt6QVi3tEEXA7zryOlVbwGnXgvntIoNLZAaJ9AyQ1RgGromnlOVlPJ9Q7mlgbWja8nQwMCEoDdtcF+ax0dz681PGw/kOBVl8W4REYnzc2J2Ftfk7FCQZo5JlQcZCw3aZqLIXlbpTHM1AK24UCsi5vq+xevPahvwM7mpWgCmGKGw3KadcMr9A5GtwN/xGiMBVB6GdinKZFp7rh8UccTkAYnHnVPlpnhSPD/8g9UgwhxZrWJUMyjCCmvdAOXn54q+j+2fdS+eVDXltcAZ7GVIthDMmZabc/uTMrJ/BHaib+dXDLNUjhZzqACgqZyQqej9CiHUEW3/p66X6eerxSkgc0TurePhUVvhSkmi1Fo30ev6+9K8wdBapw+OCfJnxFC+D1KbZhoF/5WX1NCMU4yKLzkxD4XEftEa1W9VyQHS1UTJU3vIsf6C6efvMfMJqC8=
2615
on:
2716
tags: true
2817
repo: mohankishore/python_dynamodb_lock

python_dynamodb_lock/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
__author__ = """Mohan Kishore"""
66
__email__ = 'mohankishore@yahoo.com'
77
__version__ = '0.1.0'
8+
__copyright__ = 'Copyright (C) 2018 Mohan Kishore'
Lines changed: 193 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,195 @@
11
# -*- coding: utf-8 -*-
22

3-
"""Main module."""
3+
# TODO
4+
"""
5+
module comment
6+
"""
7+
import boto3
8+
import botocore
9+
import datetime
10+
import socket
11+
import time
12+
import threading
13+
import uuid
14+
15+
16+
class DynamoDBLockClient:
17+
# TODO
18+
"""
19+
class comment
20+
"""
21+
22+
DEFAULT_TABLE_NAME = 'lockTable'
23+
DEFAULT_PARTITION_KEY_NAME = 'key'
24+
DEFAULT_SORT_KEY_NAME = 'sort_key'
25+
DEFAULT_LEASE_DURATION = datetime.timedelta(seconds=30)
26+
DEFAULT_HEARTBEAT_PERIOD = datetime.timedelta(seconds=10)
27+
28+
def __init__(self,
29+
dynamodb_client,
30+
table_name = DEFAULT_TABLE_NAME,
31+
partition_key_name = DEFAULT_PARTITION_KEY_NAME,
32+
sort_key_name = DEFAULT_SORT_KEY_NAME,
33+
owner_name = None,
34+
lease_duration = DEFAULT_LEASE_DURATION,
35+
heartbeat_period = DEFAULT_HEARTBEAT_PERIOD
36+
):
37+
"""
38+
The constructor that support default values for all/most of the arguments.
39+
40+
:param dynamodb_client: boto3.DynamoDB.Client - mandatory argument
41+
:param table_name: str - defaults to 'lockTable'
42+
:param partition_key_name: str - defaults to 'key'
43+
:param sort_key_name: str - defaults to 'sort_key'
44+
:param owner_name: str - defaults to hostname + uuid
45+
:param lease_duration: datetime.timedelta - The length of time that the lease for the lock
46+
will be granted for. i.e. if there is no heartbeat for this period of time, then
47+
the lock will be considered as expired. Defaults to 30 seconds.
48+
:param heartbeat_period: datetime.timedelta - How often to update DynamoDB to note that the
49+
instance is still running. It is recommended to make this at least 3 times smaller
50+
than the leaseDuration. Defaults to 10 seconds.
51+
"""
52+
self.uuid = uuid.uuid4()
53+
self.dynamodb_client = dynamodb_client
54+
self.table_name = table_name
55+
self.partition_key_name = partition_key_name
56+
self.sort_key_name = sort_key_name
57+
self.owner_name = owner_name if owner_name else socket.getfqdn() + self.uuid
58+
self.lease_duration = lease_duration
59+
self.heartbeat_period = heartbeat_period
60+
self.background_thread = self._start_background_thread()
61+
self.locks = {}
62+
self.shutting_down = False
63+
64+
def _start_background_thread(self):
65+
"""
66+
Creates and starts a daemon thread - that calls DynamoDBLockClient.run() method.
67+
"""
68+
background_thread = threading.Thread(
69+
name='DynamoDBLockClient-' + uuid,
70+
target=self
71+
)
72+
background_thread.daemon = True
73+
background_thread.start()
74+
return background_thread
75+
76+
def run(self):
77+
"""
78+
Iterates over all the locks owned by this lock-client, and renews their leases.
79+
"""
80+
while (True):
81+
if self.shutting_down: return None
82+
83+
start_time = datetime.datetime.utcnow()
84+
for lock in self.locks.itervalues():
85+
self.send_heartbeat(lock)
86+
end_time = datetime.datetime.utcnow()
87+
88+
if self.shutting_down: return None
89+
90+
elapsed_time = (end_time - start_time)
91+
if elapsed_time < self.heartbeat_period:
92+
time.sleep( (self.heartbeat_period - elapsed_time).total_seconds() )
93+
94+
def send_heartbeat(self, lock):
95+
"""
96+
Renews the lease for the given lock
97+
98+
:param lock: DynamoDBLock instance - that needs its lease to be renewed
99+
"""
100+
with lock.lock:
101+
try:
102+
# TODO actual impl
103+
print
104+
# update
105+
# table
106+
# keys
107+
# SET #ld = :ld, #rvn = :newRvn
108+
# attribute_exists(#pk) AND attribute_exists(#sk) AND #rvn = :rvn AND #on = :on
109+
# attribute-names
110+
# attribute-values
111+
except botocore.exceptions.ClientError as e:
112+
if e.response['Error']['Code'] == 'ConditionalCheckFailedException':
113+
# TODO: need to handle the case where the lock was "stolen" by someone else...
114+
print
115+
else:
116+
print
117+
except:
118+
print
119+
120+
121+
def close(self):
122+
"""
123+
Shuts down the background thread and releases all locks.
124+
"""
125+
self.shutting_down = True
126+
self.background_thread.join()
127+
self.release_all_locks()
128+
129+
def __exit__(self, exc_type, exc_val, exc_tb):
130+
"""
131+
Calls the close() method
132+
"""
133+
self.close()
134+
135+
def acquire_lock(self,
136+
partition_key,
137+
sort_key = None,
138+
retry_period = datetime.timedelta(seconds=2),
139+
retry_timeout = datetime.timedelta(seconds=5),
140+
additional_attributes = {}
141+
):
142+
""""""
143+
144+
def release_lock(self,
145+
lock,
146+
best_effort = False
147+
):
148+
""""""
149+
with lock.lock:
150+
try:
151+
del self.locks[lock.uuid]
152+
# TODO actual impl
153+
# delete
154+
# table
155+
# keys
156+
# attribute_exists(#pk) AND attribute_exists(#sk) AND #rvn = :rvn AND #on = :on
157+
# attribute-names
158+
# attribute-values
159+
except botocore.exceptions.ClientError as e:
160+
if e.response['Error']['Code'] == 'ConditionalCheckFailedException':
161+
# TODO: need to handle the case where the lock was "stolen" by someone else...
162+
print
163+
else:
164+
# if not best_effort: raise error
165+
print
166+
except:
167+
print
168+
169+
170+
# TODO: make this private?
171+
def release_all_locks(self):
172+
""""""
173+
for lock in self.locks.itervalues():
174+
self.release_lock(lock)
175+
176+
# get_lock
177+
# get_all_locks
178+
179+
180+
181+
class DynamoDBLock:
182+
# TODO
183+
"""
184+
class comment
185+
"""
186+
187+
def __init__(self,
188+
partition_key,
189+
sort_key = None,
190+
retry_period = datetime.timedelta(seconds=2),
191+
retry_timeout = datetime.timedelta(seconds=5),
192+
additional_attributes = {}
193+
):
194+
# TODO
195+
""""""

requirements_dev.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ coverage==4.5.1
88
Sphinx==1.7.8
99
twine==1.11.0
1010
sphinx_rtd_theme==0.4.1
11+
boto3==1.8.6
12+
botocore==1.11.6

0 commit comments

Comments
 (0)