How to execute more code after sending an HTTP response in a viewfunction?

90 views
Skip to first unread message

Fluoborate

unread,
Jul 9, 2009, 4:19:03 PM7/9/09
to Django users
Hello All,

I am afraid that I might have to write my own middleware to do this. I
really want to do something like the following:

#In views.py:

def welcome( request ):
return HttpResponse( "Welcome to my website" )
#No code after the 'return' statement will ever be executed, but I
wish it would:
time-consuming_function( request )

Why do I want to do this? My website feels a bit slow to use, because
it needs to do time-consuming_function. The content of the HTTP
response does not depend on time-consuming_function, so why should the
user have to wait for it? Unfortunately, time-consuming_function DOES
depend on the HttpRequest object and other local variables only
available in the scope of the view function, so it is much more
convenient to execute time-consuming_function inside the view
function.

Here is how I could do it in middleware, if nobody has an easier
solution:

@this_view_function_has_a_callback
def welcome( request ):
return HttpResponse( "Welcome to my website" ), time-
consuming_function, { "request" : request }

I would have to write middleware to unpack the tuple returned by the
view function and do the proper stuff with each piece. What a hassle.

Has anyone already written that? Is there some much smarter and more
graceful work-around? Thank you all so much.

Javier Guerra

unread,
Jul 9, 2009, 4:30:17 PM7/9/09
to django...@googlegroups.com
On Thu, Jul 9, 2009 at 3:19 PM, Fluoborate<moto...@gmail.com> wrote:
>
> Hello All,
>
> I am afraid that I might have to write my own middleware to do this. I
> really want to do something like the following:
>
> #In views.py:
>
> def welcome( request ):
>    return HttpResponse( "Welcome to my website" )
>    #No code after the 'return' statement will ever be executed, but I
> wish it would:
>    time-consuming_function( request )


the generic answer is to use a queue service (like rabbitMQ, or lots
of others). a simplistic implementation is just stashing some
parameters into a DB table and use a cron job to 'execute' them
(called Ghetto queue in the 'scaling django' presentation).

there are some 'same process' python queues out there, mostly just a
thin wrapper on a python Queue object (which has task_done() and
join() methods just for this). but for multi-process Django i don't
think it would work.

maybe is it possible to use signals like this? i haven't checked the
source, but it seems plausible to have them dispatched _after_ the
request is serviced.

--
Javier

Javier Guerra

unread,
Jul 9, 2009, 4:59:49 PM7/9/09
to django...@googlegroups.com
On Thu, Jul 9, 2009 at 3:30 PM, Javier Guerra<jav...@guerrag.com> wrote:
> maybe is it possible to use signals like this? i haven't checked the
> source,  but it seems plausible to have them dispatched _after_ the
> request is serviced.

no, it doesn't work like that. also, it seems that a custom
middleware wouldn't work, given the way the WSGIHandler() is written
(the last thing it does is to return the response content).

go the message queue way.

--
Javier

Rodrigue

unread,
Jul 10, 2009, 5:11:21 AM7/10/09
to Django users
Kicking off threads could be a solution, if you want your time-
consuming_function to run in the same process(es) as django.
Otherwise, you'll need to either create new processes or use some
inter process communication solution (socket, http, message
queue, ...)

In the first situation, make sure you that you either don't access the
database via the django ORM, or manage the db connection yourself.
Django closes db connection when the HTTP Response is returned, using
signals. If you play with the db after the request/response cycle has
completed, django will be unaware of your db connections and won't
close them.

Rodrigue

Tom Evans

unread,
Jul 10, 2009, 6:13:14 AM7/10/09
to django...@googlegroups.com

Would doing the expensive function in a generator be enough? Eg:

def welcome(request):
def worker():
yield "Welcome to my website"
yield time_consuming_function(request)
return HttpResponse(worker())

The user will see the 'Welcome to my website' immediately, and the page
will continue to load in the background, performing your time consuming
function.

Cheers

Tom

Reply all
Reply to author
Forward
0 new messages