What a n00b!

Celery jobs unable to access objects when queued by post_save signal in Django

I ran into a fun issue this week, working on job queueing in ShutterGuides. We use Django for the app server and django-celery for job queueing in the background. In our case, we added a post_save signal to our Guide model to trigger an import of the photos in the background.

The code was pretty typical and worked great in development, triggering after a save and throwing the job onto the queue. The workers consumed the jobs and pulled in photos exactly as expected.

However, I noticed that when using MySQL, this task seemed to not do the right thing as it found nothing to import. As it turns out, this was because the post_save signal in Django is fired before the MySQL transaction has been applied. So, if a worker picks it up off the queue immediately, it may not have access to the object in the database yet; or in the case of updates, will not have access to the newest version of the object.

The solution in the StackOverflow question referenced above seems to indicate something like Celery would solve this, which of course isn't true since the job can fire before the transaction finishes as well. My solution was fairly simple, though perhaps a bit of a workaround:

- ImportPhotosTask.delay(instance) + ImportPhotosTask.apply_async([instance], countdown=2)

There's also a small patch on Github to add a post_commit signal to Django, but I try to stay away from anything that calls itself a "monkey-patch" right in the description. Might be good code, got stopped at that statement..


Comments powered by Disqus