Add a docstring and some comments

This commit is contained in:
richard-dds 2019-09-17 11:30:07 -04:00
parent 23261da3af
commit 7004f7d37e

View File

@ -7,12 +7,22 @@ from atst.domain.exceptions import ClaimFailedException
@contextmanager @contextmanager
def claim_for_update(resource, minutes=30): def claim_for_update(resource, minutes=30):
"""
Claim a mutually exclusive expiring hold on a resource.
Uses the database as a central source of time in case the server clocks have drifted.
Args:
resource: A SQLAlchemy model instance with a `claimed_until` attribute.
minutes: The maximum amount of time, in minutes, to hold the claim.
"""
Model = resource.__class__ Model = resource.__class__
claim_until = func.now() + func.cast( claim_until = func.now() + func.cast(
sql.functions.concat(minutes, " MINUTES"), Interval sql.functions.concat(minutes, " MINUTES"), Interval
) )
# Optimistically query for and update the resource in question. If it's
# already claimed, `rows_updated` will be 0 and we can give up.
rows_updated = ( rows_updated = (
db.session.query(Model) db.session.query(Model)
.filter( .filter(
@ -26,11 +36,14 @@ def claim_for_update(resource, minutes=30):
if rows_updated < 1: if rows_updated < 1:
raise ClaimFailedException(resource) raise ClaimFailedException(resource)
# Fetch the claimed resource
claimed = db.session.query(Model).filter_by(id=resource.id).one() claimed = db.session.query(Model).filter_by(id=resource.id).one()
try: try:
# Give the resource to the caller.
yield claimed yield claimed
finally: finally:
# Release the claim.
db.session.query(Model).filter(Model.id == resource.id).filter( db.session.query(Model).filter(Model.id == resource.id).filter(
Model.claimed_until != None Model.claimed_until != None
).update({"claimed_until": None}, synchronize_session="fetch") ).update({"claimed_until": None}, synchronize_session="fetch")