django_replicated
django_replicated copied to clipboard
Context leakage when using decorators
Issue
We faced a strange problem. Some of the queries inside of some views that are not decorated with the @use_slave
were getting routed to the slave db instances.
After a couple of hours spent debugging found the reproduction routine.
Reproduce
Consider:
@use_slave
def v1(request, *args, **kwargs):
raise Exception('!')
...
def v2(request, *args, **kwargs):
print(Model2.objects.all()) # <--- Routed to the slave
...
Decorators are using ReplicationMiddleware
but ReplicationMiddleware
is not implementing process_exception
and if the exception is not handled, the ReplicationMiddleware#process_response
and routers.reset()
are not called at all. Hence, the _context
on the router remains dirty.
So any v2
call that is happening after the v1
raising an exception get routed to the slave instances.
Fix
Just wrapped the django_replicated decorator just like:
def use_replicas(function_based_view):
def inner(*args, **kwargs):
from django_replicated.decorators import use_slave
from django_replicated.utils import routers
try:
return use_slave(function_based_view)(*args, **kwargs)
except Exception as e:
routers.reset()
raise e
return inner