Add the ability to select for update within transactions to fix some write after read hazards. Fix a bug in extend_processing.
This commit is contained in:
parent
e8b25ad7ff
commit
64750e31fc
4 changed files with 37 additions and 15 deletions
|
@ -1,6 +1,6 @@
|
|||
from datetime import datetime, timedelta
|
||||
|
||||
from data.database import QueueItem, db
|
||||
from data.database import QueueItem, db, db_for_update
|
||||
from util.morecollections import AttrDict
|
||||
|
||||
|
||||
|
@ -41,6 +41,9 @@ class WorkQueue(object):
|
|||
def _name_match_query(self):
|
||||
return '%s%%' % self._canonical_name([self._queue_name] + self._canonical_name_match_list)
|
||||
|
||||
def _item_by_id_for_update(self, queue_id):
|
||||
return db_for_update(QueueItem.select().where(QueueItem.id == queue_id)).get()
|
||||
|
||||
def update_metrics(self):
|
||||
if self._reporter is None:
|
||||
return
|
||||
|
@ -91,7 +94,7 @@ class WorkQueue(object):
|
|||
|
||||
item = None
|
||||
try:
|
||||
db_item = avail.order_by(QueueItem.id).get()
|
||||
db_item = db_for_update(avail.order_by(QueueItem.id)).get()
|
||||
db_item.available = False
|
||||
db_item.processing_expires = now + timedelta(seconds=processing_time)
|
||||
db_item.retries_remaining -= 1
|
||||
|
@ -111,14 +114,14 @@ class WorkQueue(object):
|
|||
|
||||
def complete(self, completed_item):
|
||||
with self._transaction_factory(db):
|
||||
completed_item_obj = QueueItem.get(QueueItem.id == completed_item.id)
|
||||
completed_item_obj = self._item_by_id_for_update(completed_item.id)
|
||||
completed_item_obj.delete_instance()
|
||||
self._currently_processing = False
|
||||
|
||||
def incomplete(self, incomplete_item, retry_after=300, restore_retry=False):
|
||||
with self._transaction_factory(db):
|
||||
retry_date = datetime.utcnow() + timedelta(seconds=retry_after)
|
||||
incomplete_item_obj = QueueItem.get(QueueItem.id == incomplete_item.id)
|
||||
incomplete_item_obj = self._item_by_id_for_update(incomplete_item.id)
|
||||
incomplete_item_obj.available_after = retry_date
|
||||
incomplete_item_obj.available = True
|
||||
|
||||
|
@ -128,12 +131,12 @@ class WorkQueue(object):
|
|||
incomplete_item_obj.save()
|
||||
self._currently_processing = False
|
||||
|
||||
def extend_processing(self, seconds_from_now, minimum_extension=MINIMUM_EXTENSION):
|
||||
def extend_processing(self, item, seconds_from_now, minimum_extension=MINIMUM_EXTENSION):
|
||||
with self._transaction_factory(db):
|
||||
queue_item = QueueItem.get(QueueItem.id == self.id)
|
||||
queue_item = self._item_by_id_for_update(item.id)
|
||||
new_expiration = datetime.utcnow() + timedelta(seconds=seconds_from_now)
|
||||
|
||||
# Only actually write the new expiration to the db if it moves the expiration some minimum
|
||||
if new_expiration - queue_item.processing_expires > minimum_extension:
|
||||
queue_item.processing_expires = new_expiration
|
||||
queue_item.save()
|
||||
queue_item.save()
|
||||
|
|
Reference in a new issue