Projet

Général

Profil

0002-api-restart-fillslot-on-IntegrityError-53367.patch

Benjamin Dauvergne, 27 avril 2021 15:14

Télécharger (3,76 ko)

Voir les différences:

Subject: [PATCH 2/2] api: restart fillslot on IntegrityError (#53367)

 chrono/api/views.py | 45 ++++++++++++++++++++++++++++++---------------
 1 file changed, 30 insertions(+), 15 deletions(-)
chrono/api/views.py
19 19
import itertools
20 20
import uuid
21 21

  
22
from django.db import transaction
22
from django.db import IntegrityError, transaction
23 23
from django.db.models import Prefetch, Q
24 24
from django.http import Http404, HttpResponse
25 25
from django.shortcuts import get_object_or_404
......
918 918
    def post(self, request, agenda_identifier=None, event_identifier=None, format=None):
919 919
        return self.fillslot(request=request, agenda_identifier=agenda_identifier, format=format)
920 920

  
921
    def fillslot(self, request, agenda_identifier=None, slots=[], format=None):
921
    def fillslot(self, request, agenda_identifier=None, slots=[], format=None, retry=False):
922 922
        multiple_booking = bool(not slots)
923 923
        try:
924 924
            agenda = Agenda.objects.get(slug=agenda_identifier)
......
1138 1138
            # booking requires real Event objects (not lazy Timeslots);
1139 1139
            # create them now, with data from the slots and the desk we found.
1140 1140
            events = []
1141
            for start_datetime in datetimes:
1142
                event = Event.objects.create(
1143
                    agenda=available_desk.agenda,
1144
                    slug=str(uuid.uuid4()),  # set slug to avoid queries during slug generation
1145
                    meeting_type=meeting_type,
1146
                    start_datetime=start_datetime,
1147
                    full=False,
1148
                    places=1,
1149
                    desk=available_desk,
1150
                )
1151
                if resources:
1152
                    event.resources.add(*resources)
1153
                events.append(event)
1141
            try:
1142
                with transaction.atomic():
1143
                    for start_datetime in datetimes:
1144
                        event = Event.objects.create(
1145
                            agenda=available_desk.agenda,
1146
                            slug=str(uuid.uuid4()),  # set slug to avoid queries during slug generation
1147
                            meeting_type=meeting_type,
1148
                            start_datetime=start_datetime,
1149
                            full=False,
1150
                            places=1,
1151
                            desk=available_desk,
1152
                        )
1153
                        if resources:
1154
                            event.resources.add(*resources)
1155
                        events.append(event)
1156
            except IntegrityError:
1157
                # "optimistic concurrency control", between our availability
1158
                # check with get_all_slots() and now, new event can have been
1159
                # created and conflict with the events we want to create, and
1160
                # so we get an IntegrityError exception. In this case we
1161
                # restart the fillslot() from the begginning to redo the
1162
                # availability check and return a proper error to the client.
1163
                #
1164
                # To prevent looping, we still raise the IntegrityError during
1165
                # the second run of fillslot().
1166
                if retry:
1167
                    raise
1168
                return self.fillslot(request, agenda_identifier=agenda_identifier, slots=slots, retry=True)
1154 1169
        else:
1155 1170
            # convert event recurrence identifiers to real event slugs
1156 1171
            for i, slot in enumerate(slots.copy()):
1157
-