mirror of
https://github.com/pretix/pretix.git
synced 2026-08-15 11:36:27 +00:00
Very basic locking mechanism for quotas
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0007_auto_20150212_0939'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='quota',
|
||||
name='locked',
|
||||
field=models.DateTimeField(null=True, blank=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
||||
@@ -1,6 +1,7 @@
|
||||
from itertools import product
|
||||
import copy
|
||||
import uuid
|
||||
import time
|
||||
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
@@ -1041,6 +1042,10 @@ class Quota(Versionable):
|
||||
blank=True,
|
||||
verbose_name=_("Variations")
|
||||
)
|
||||
locked = models.DateTimeField(
|
||||
null=True, blank=True
|
||||
)
|
||||
locked_here = False
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Quota")
|
||||
@@ -1105,12 +1110,31 @@ class Quota(Versionable):
|
||||
|
||||
return Quota.AVAILABILITY_OK, self.size - paid_orders - pending_valid_orders - valid_cart_positions
|
||||
|
||||
class LockTimeoutException(Exception):
|
||||
pass
|
||||
|
||||
def lock(self):
|
||||
"""
|
||||
Issue a lock on this quota so nobody can take tickets from this quota until
|
||||
you release the lock
|
||||
you release the lock.
|
||||
|
||||
Raises an Quota.LockTimeoutException if the quota is locked every time we
|
||||
try to obtain a lock.
|
||||
"""
|
||||
pass
|
||||
retries = 5
|
||||
for i in range(retries):
|
||||
dt = now()
|
||||
updated = Quota.objects.current.filter(
|
||||
identity=self.identity, locked__isnull=True,
|
||||
version_end_date__isnull=True
|
||||
).update(
|
||||
locked=dt
|
||||
)
|
||||
if updated:
|
||||
self.locked_here = dt
|
||||
return True
|
||||
time.sleep(2 ** i / 100)
|
||||
raise Quota.LockTimeoutException()
|
||||
|
||||
def release(self, force=False):
|
||||
"""
|
||||
@@ -1118,7 +1142,15 @@ class Quota(Versionable):
|
||||
the lock will only be released if it was issued in _this_ python
|
||||
representation of the database object.
|
||||
"""
|
||||
pass
|
||||
if not self.locked_here and not force:
|
||||
return False
|
||||
updated = Quota.objects.current.filter(
|
||||
identity=self.identity,
|
||||
version_end_date__isnull=True
|
||||
).update(
|
||||
locked=None
|
||||
)
|
||||
return updated
|
||||
|
||||
|
||||
class Order(Versionable):
|
||||
|
||||
@@ -94,13 +94,22 @@ class CartAdd(EventViewMixin, CartActionMixin, View):
|
||||
price = item.execute_restrictions() if variation is None else variation.execute_restrictions()
|
||||
|
||||
if price is False:
|
||||
msg_some_unavailable = True
|
||||
messages.error(self.request,
|
||||
_('Some of the items you selected were no longer available. '
|
||||
'Please see below for details.'))
|
||||
if not msg_some_unavailable:
|
||||
msg_some_unavailable = True
|
||||
messages.error(self.request,
|
||||
_('Some of the items you selected were no longer available. '
|
||||
'Please see below for details.'))
|
||||
continue
|
||||
|
||||
quotas = list(item.quotas.all()) if variation is None else list(variation.quotas.all())
|
||||
if len(quotas) == 0:
|
||||
if not msg_some_unavailable:
|
||||
msg_some_unavailable = True
|
||||
messages.error(self.request,
|
||||
_('Some of the items you selected were no longer available. '
|
||||
'Please see below for details.'))
|
||||
continue
|
||||
|
||||
quota_ok = i[2]
|
||||
try:
|
||||
for quota in quotas:
|
||||
@@ -132,6 +141,12 @@ class CartAdd(EventViewMixin, CartActionMixin, View):
|
||||
price=price,
|
||||
expires=now() + timedelta(minutes=30)
|
||||
)
|
||||
except Quota.LockTimeoutException:
|
||||
if not msg_some_unavailable:
|
||||
msg_some_unavailable = True
|
||||
messages.error(self.request,
|
||||
_('We were not able to process your request completely as the '
|
||||
'server was too busy. Please try again.'))
|
||||
finally:
|
||||
for quota in quotas:
|
||||
quota.release()
|
||||
|
||||
Reference in New Issue
Block a user