Как обрабатывать устаревшие экземпляры модели при длительном обновлении базы данных в Django/Postgres?

Контекст:

Веб-приложение среднего размера

Django 3.2, DRF 3.13, python 3.8

Хостинг в облаке Google и управление движком goole kubernetes engine

Google CloudSQL для PostgreSQL (v. 9)



class Park(models.Model):
    <some fields>


class City(models.Model):
    foo = models.IntegerField()
    # bar and baz are populated from a microservice at City creation
    bar = models.IntegerField()
    # baz was recently added and is null for some cities
    baz = models.IntegerField(null=True) 

    @property
    def update_from_microservice(self):
        """Updates the row by making a call to a microservice hosted in the same cluster as the Django App"""
        new_data = call_to_microservice(self.foo)
        self.bar = new_data["bar"]
        self.baz = new_data["baz"]
        self.save()

    @property
    def get_data(self)
        """Helper method that returns some structured data from the instance"""
        return {"bar": self.bar, "baz": self.baz}



class ParkListView(generics.ListAPIView):
    serializer = ParkSerializer
    http_method_names = ["get"]

    def get_queryset(self):
        return Park.objects.filter()

    def get_serializer_context(self):
        context = super().get_serializer_context()
        
        # Get the city from the uri `/parks/<int:city_foo>/`
        foo = kwargs.get("city_foo")
        this_city = City.objects.get(foo=foo))
        city_data = this_city.get_data()
        
        # Check that the expected data is present.  
        if None in city_data.values():
           
           # If data is missing, try updating the fields
           # Tests indicate this step works as expected,
           # since the update_from_microservice() refers to self, this instance should
           # get the updated values once the microservice returns
           this_city.update_from_microservice()
           
           # Get the data again
           city_data = this_city.get_data()
           
           if None in city_data.values():
               # If data is still missing, log an error, 
               # but return the context data anyway
               log_error(f"City with foo = {foo} returned empty values"}
        
        # Update the context with whatever city_data we have and return it.
        context.update({"city_data": city_data})
        
        return context

Проблема в том, что ошибка регистрируется почти для каждого города, в котором изначально отсутствуют данные. При тестировании метод get_data_from_microservice работает правильно, но второй вызов this_city.get_data() возвращает устаревшие данные.

Мы могли бы заполнить недостающие данные, но мы предпочли обновлять их по мере необходимости из-за последующих последствий большого одновременного изменения таблицы.

Когда я проверяю базу данных для City, вызвавшего ошибку, данные были обновлены с не нулевыми значениями (так что строка обновляется, но это не отображается в методе).

Возможные причины:

  1. According to our Datadog monitoring, a call to the microservice accounts for ~10 - 50 ms depending on load. I expected the view to wait for the call the microservice to complete, but am I correct in that?

  2. City is a fairly fat model with a few million rows. There is a noticeable lag in the django shell when retrieving an instance of City. I'd expected that lag to just cause a slight performance hit. But again, am I wrong in expecting that code execution will wait until the model update is complete?

  3. Is this an artifact of our setup Google Cloud SQL? Are there any settings I should ask our devops team to look into that might cause our db to return a premature transaction complete signal?

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