Django - Задержка репликации

Пререквизиты:

class Task(models.Model):
    class TaskStatus(models.TextChoices):
        HIDDEN = 'hidden', _('hidden')
        NEW = 'new', _('new')
        IN_PROGRESS = 'in_progress', _('in progress')
        DONE = 'done', _('done')
        FAILED = 'failed', _('failed')
        PLANNED = 'planned', _('planned')
        REVOKED = 'revoked', _('revoked')

    title = models.CharField(max_length=500)
    performer = models.ForeignKey(User, on_delete=models.CASCADE)
    status = models.CharField(choices=TaskStatus.choices, default=TaskStatus.HIDDEN, max_length=25)


class TaskTransition(models.Model):
    task = models.ForeignKey('tasks.Task', on_delete=models.CASCADE, related_name='transitions')
    actor = models.ForeignKey(User, on_delete=models.RESTRICT, related_name='transitions')
    old_status = models.CharField(choices=TaskStatus.choices, max_length=25)
    new_status = models.CharField(choices=TaskStatus.choices, max_length=25)


class TaskView(ModelViewSet):
    queryset = Task.objects.all()
    serializer = TaskSerializer


class CreateTaskTransitionView(mixins.RetrieveModelMixin, generics.CreateAPIView):
    serializer_class = CreateTaskTransitionSerializer


class CreateTaskTransitionSerializer(serializers.ModelSerializer):
    task = serializers.HiddenField(default=HiddenTaskField())
    actor = serializers.HiddenField(default=serializers.CurrentUserDefault())

    class Meta:
        model = TaskTransition
        fields = '__all__'

    def validate(self, attrs):
        # allowed status transitions:
        # hidden > new
        # new > in_progress, failed
        # in_progress > done, failed
        return attrs

    def save(self, **kwargs):
        task = self.validated_data['task']
        new_status = self.validated_data['new_status']

        TaskTransition.objects.create(
            task=task,
            new_status=new_status,
            old_status=task.status,
            actor=self.validated_data['actor']
        )

        task.status = new_status
        task.save()

        return {}

Мы используем две базы данных. Первая default для записи и replica для чтения.

Из-за валидации, как вы видите, может быть выполнен только один уникальный переход задачи. Но иногда случается, что может быть несколько одинаковых переходов. Например, 5 переходов in_progress > done.

При получении экземпляра задачи задача имеет неактуальный статус.

Очевидно, что это происходит из-за задержки репликации: в CreateTaskTransitionSerializer задача читается из реплики с не обновленным (актуальным) статусом.

Так что я подумал, что для решения этой проблемы retrieve действие TaskView должно читаться из default, верно? Если да, то как я могу это сделать? Примерно так:

class TaskView(models.Model):
    def get_queryset(self):
        qs = super().get_queryset(request)
        if self.action == 'retrieve':
             qs = qs.using('default') 
        return qs

?

Вернуться на верх