Как обрабатывать устаревшие экземпляры модели при длительном обновлении базы данных в 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, вызвавшего ошибку, данные были обновлены с не нулевыми значениями (так что строка обновляется, но это не отображается в методе).
Возможные причины:
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?
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?
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?