perf: Ticket set serial number add lock

pull/13885/head
feng 2024-08-05 16:34:06 +08:00 committed by Bryan
parent 5e69c03cb7
commit c646084c51
1 changed files with 19 additions and 13 deletions

View File

@ -14,7 +14,8 @@ from accounts.const import AliasAccount
from common.db.encoder import ModelJSONFieldEncoder from common.db.encoder import ModelJSONFieldEncoder
from common.db.models import JMSBaseModel from common.db.models import JMSBaseModel
from common.exceptions import JMSException from common.exceptions import JMSException
from common.utils import reverse from common.utils import reverse, get_logger
from common.utils.lock import DistributedLock
from common.utils.timezone import as_current_tz from common.utils.timezone import as_current_tz
from orgs.models import Organization from orgs.models import Organization
from orgs.utils import tmp_to_org from orgs.utils import tmp_to_org
@ -26,6 +27,8 @@ from tickets.errors import AlreadyClosed
from tickets.handlers import get_ticket_handler from tickets.handlers import get_ticket_handler
from ..flow import TicketFlow from ..flow import TicketFlow
logger = get_logger(__file__)
__all__ = [ __all__ = [
'Ticket', 'TicketStep', 'TicketAssignee', 'Ticket', 'TicketStep', 'TicketAssignee',
'SuperTicket', 'SubTicketManager' 'SuperTicket', 'SubTicketManager'
@ -374,25 +377,28 @@ class Ticket(StatusMixin, JMSBaseModel):
date_created = as_current_tz(self.date_created) date_created = as_current_tz(self.date_created)
date_prefix = date_created.strftime('%Y%m%d') date_prefix = date_created.strftime('%Y%m%d')
ticket = Ticket.objects.all().select_for_update().filter( ticket = Ticket.objects.filter(
serial_num__startswith=date_prefix serial_num__startswith=date_prefix
).order_by('-date_created').first() ).order_by('-serial_num').first()
last_num = 0 last_num = 0
if ticket: if ticket:
last_num = ticket.serial_num[8:] last_num = ticket.serial_num[8:]
last_num = int(last_num) last_num = int(last_num)
num = '%04d' % (last_num + 1) num = '%04d' % (last_num + 1)
return '{}{}'.format(date_prefix, num) return f'{date_prefix}{num}'
def set_serial_num(self): def set_serial_num(self):
if self.serial_num: if self.serial_num:
return return
lock_key = 'TICKET_LOCK_SET_SERIAL_NUM'
with DistributedLock(lock_key):
try: try:
self.serial_num = self.get_next_serial_num() self.serial_num = self.get_next_serial_num()
self.save(update_fields=('serial_num',)) self.save(update_fields=('serial_num',))
except IntegrityError as e: except IntegrityError as e:
logger.error(f'Set ticket serial number error: {e}')
if e.args[0] == 1062: if e.args[0] == 1062:
# 虽然做了 `select_for_update` 但是每天的第一条工单仍可能造成冲突 # 虽然做了 `select_for_update` 但是每天的第一条工单仍可能造成冲突
# 但概率小,这里只报错,用户重新提交即可 # 但概率小,这里只报错,用户重新提交即可