rabbitmq + celery + django + celery.views.task_status ... simple example?

586 views
Skip to first unread message

wawa wawawa

unread,
Nov 2, 2010, 1:12:20 PM11/2/10
to django...@googlegroups.com
Hi All,

So, I've got my django app, rabbitmq and celery working and processing
my uploaded files. Next step is to get the client to display status
results provided by JSON, ultimately refreshing to a results page when
complete.

I'm a little new to JSON / AJAX (AJAJ!) and I'm struggling a little
with the templates and views part.

Are there any easy examples out there?

I can't seem to find any!

Many thanks in advance for any suggestions.

Cheers

W

Prashanth

unread,
Nov 3, 2010, 2:09:22 AM11/3/10
to django...@googlegroups.com
On Tue, Nov 2, 2010 at 10:42 PM, wawa wawawa <wazaw...@gmail.com> wrote:
Hi All,

So, I've got my django app, rabbitmq and celery working and processing
my uploaded files. Next step is to get the client to display status
results provided by JSON, ultimately refreshing to a results page when
complete.

I'm a little new to JSON / AJAX (AJAJ!) and I'm struggling a little
with the templates and views part.

Are there any easy examples out there?



Is the expectation like user will upload a file and will see a result? if that is case why are using celery? b-list has a ajax example[1]. BTW,  if you are trying to upload a file using ajax you need to create iframe using javascript, you might want to use jsupload[2]  


[2] http://valums.com/
--
regards,
Prashanth
twitter: munichlinux
blog: honeycode.in
irc: munichlinux, JSLint, munichpython.

wawa wawawa

unread,
Nov 3, 2010, 5:14:15 AM11/3/10
to django...@googlegroups.com
Hi,

I'm using a message queue because the task is really "offline" and
could take 1sec or 30 seconds (or longer).

I'll look at b-list. Thankyou

W

> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To post to this group, send email to django...@googlegroups.com.
> To unsubscribe from this group, send email to
> django-users...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/django-users?hl=en.
>

Tom Evans

unread,
Nov 3, 2010, 6:10:20 AM11/3/10
to django...@googlegroups.com

Sure. I have a TV recording system built using Django (the UI is web
based), which records TV shows to disk in MPEG2 format. I then use the
whole celery stack to convert those video files into something that I
can then load up onto my ipad/iphone.

The transcoding is initiated by a user clicking an icon on the episode
page, which triggers an AJAX call, which eventually calls this
function:

def setup_transcode_episode(episode):
data = { 'valid': False, }
if episode.media:
file = unicode(episode.media)
rv = transcode_episode_for_ipad.delay(file=file, episode_id=episode.id)
tm, created = TaskMeta.objects.get_or_create(task_id=rv.task_id)
episode.ipad_media = tm
episode.save()
data['task_id'] = rv.task_id
data['valid'] = True
return data

The data dictionary is returned back to the client, which now
periodically polls a view for status, using the task_id.

The task that is invoked, transcode_episode_for_ipad, looks like this:

@task
def transcode_episode_for_ipad(file, episode_id, **kwargs):
args = make_ipad_encoder_args(file=file)
out = args[-1]
ffmpeg = FFmpegProgressMonitor(file=file, task_id=kwargs['task_id'],
args=args)
rv = ffmpeg.process()
episode = TVEpisode.objects.get(id=episode_id)
dir, fn = out.rsplit('/', 1)
imedia = MplayerFileMedia.objects.create(directory=dir, file=fn)
episode.ipad_media = imedia
episode.save()
return rv

This is pretty straight-forward, I simply produce the arguments for
ffmpeg, and then process it, monitoring the output of the ffmpeg to
give me hints about how long through the transcoding process we are,
which I then store in memcache, to avoid requiring a database hit to
find out the status of the task.
This is easier than it sounds, every <n> frames, ffmpeg prints out a
line indicating how far through the file it is. Just monitor the
output and update the cache as appropriate.

The way my models are set up, TVEpisode.ipad_media is a generic
foreign key, so while transcoding is taking place it points at the
TaskMeta object, which contains the task id. This allows us to know
that the task is underway in the background, even if we didn't
initiate it ourselfs, and use that information to poll for status etc
as appropriate.

Cheers

Tom

wawa wawawa

unread,
Nov 3, 2010, 6:16:34 AM11/3/10
to django...@googlegroups.com
You Sir, are awesome.

I think this seems to be exactly what I was looking for...

Can I ask for JS code that does the periodic polling from the client
please and possibly the appropriate bits of the template?

Many thanks!

W

Tom Evans

unread,
Nov 3, 2010, 6:36:05 AM11/3/10
to django...@googlegroups.com
On Wed, Nov 3, 2010 at 10:16 AM, wawa wawawa <wazaw...@gmail.com> wrote:
> You Sir, are awesome.
>
> I think this seems to be exactly what I was looking for...
>
> Can I ask for JS code that does the periodic polling from the client
> please and possibly the appropriate bits of the template?
>
> Many thanks!
>
> W
>

Sure. In the main page view, I check to see whether I have transcoded
or started transcoding the episode, and set context variables as
appropriate:

if episode.ipad_media:
if hasattr(episode.ipad_media, 'task_id'):
from transcoding.utils import get_task_progress
data['ipad_media_class'] = 'transcoding'
data['ipad_media_progress'] = (episode.ipad_media.task_id,
get_task_progress(episode.ipad_media.task_id))
else:
data['ipad_media_class'] = 'good'
else:
data['ipad_media_class'] = 'bad'

This is rendered into a widget on the page:

{% if episode.media %}
<div class='pushbutton'>
<div class='button play'>Play episode</div>
<div class='button ipad_{{ ipad_media_class }} {{ ipad_media_class }}'>
{% if ipad_media_progress %}
Transcoding to ipad
<div class='pct' id='{{ ipad_media_progress.0 }}'>{{
ipad_media_progress.1 }} %</div>
{% else %}
Transcode to ipad
{% endif %}
</div>
</div>
{% endif %}


Then, during page load, I configure an observer to update each
progress widget (I use the prototype JS framework):

$$('div.pct').each(function(ctl) {
new Ajax.PeriodicalUpdater(ctl, '{% url transcode_task_status_ajax %}', {
method: 'get',
asynchronous: true,
frequency: 3,
decay: 2,
parameters: { task_id: ctl.id }
});
});

That view is trivial, since it just updates the appropriate div with
the current percentage:

def transcode_task_status_ajax(request):
from transcoding.utils import get_task_progress
task_id = request.GET.get('task_id')
return HttpResponse(u'%s %%' % get_task_progress(task_id))


Cheers

Tom

wawa wawawa

unread,
Nov 3, 2010, 6:43:45 AM11/3/10
to django...@googlegroups.com
Tom - many thanks again.

This is good stuff.

W

Reply all
Reply to author
Forward
0 new messages