Opened 4 years ago

Closed 4 years ago

Last modified 4 years ago

#32049 closed Bug (invalid)

Database connection differs between Middleware and views running under ASGI. — at Version 4

Reported by: Hugo Osvaldo Barrera Owned by: nobody
Component: HTTP handling Version: 3.1
Severity: Normal Keywords: ASGI
Cc: Andrew Godwin Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Carlton Gibson)

(Was: Middleware behaviour inconsistent between runserver and daphne)

All my views expect a particular middleware to have run (it detects the current tenant based on the request's host).

I'm having an issue which only occurs on production, but I could not reproduce in development mode (even with DEBUG=False) nor via unit tests.

After just inspecting stack traces, it seems that when handler404 is run, behaviour varies between runserver and daphne.

Looking at the backtrace of my handler404 function:

  • When running django-admin runserver 0.0.0.0:8000, all my middlewares are in my backtrace, meaning they've gotten executed and the function is called in their context.
  • When running daphne myapp.asgi:application --bind 0.0.0.0 --port 8000 --http-timeout 90, I put a tracepoint in my handler404, and the middleware are not in the backtrace. It seems that the view is run outside the context of these middlewares.

I haven't been able to find anything in the docs clarifying whether error handlers should expect middleware to have run successfully, but whatever the intended behaviour is, it should be consistent across the two.

Change History (4)

comment:1 by Carlton Gibson, 4 years ago

Hi Hugo. Can you provide a minimal project that reproduces this please?

comment:2 by Hugo Osvaldo Barrera, 4 years ago

This reproduces the issue. Hope it's clear enough.

https://github.com/WhyNotHugo/django-32049

comment:3 by Carlton Gibson, 4 years ago

Cc: Andrew Godwin added
Keywords: ASGI added
Resolution: invalid
Status: newclosed

This is an interesting one. The issue is the way the ASGIHandler runs your code in separate threads. (The bottom-line will be that what you're trying to do isn't supported: you're going to have to find a thread-safe way of doing this if you want to use ASGI here, now.)

Your middleware sets connection.tenant in Thread 1. Via the DefaultConnectionProxy this fetches and sets the property on the "default" connection for Thread 1.
Your view is then run on Thread 2. Attempting to get connection.tenant the DefaultConnectionProxy fetches the "default" connection for Thread 2.
Since DB connections are not shared between thread, this is not the same connection, so the tenant attribute you set doesn't exist.

I'll cc Andrew since it's an interesting case, but it's expected behaviour. ASGI/async implies/requires much more thought about what thread you're going to be running on here, and hence how you pass this kind of info around.

comment:4 by Carlton Gibson, 4 years ago

Description: modified (diff)
Summary: Middleware behaviour inconsistent between runserver and daphneDatabase connection differs between Middleware and views running under ASGI.
Note: See TracTickets for help on using tickets.
Back to Top