Flower: Embedding Flower in Django?

Created on 12 Dec 2017  路  8Comments  路  Source: mher/flower

Is it possible to embed Flower in a Django? I have a Django application, which uses Celery to run a lot of background tasks, and I've found Flower works very reliably to show which tasks are running. However, it's quite cumbersome to setup a separate Apache site just to run Flower, and even then the security features in Flower aren't as robust as those in Django. Ideally, I'd like to publish Flower's web pages through Django's framework, so it can re-use Django's login as well as be managed through the same Apache site. How difficult would that be?

Most helpful comment

If you have nginx in front of django, you can add this to your nginx config

        location /flower-internal/static/ {
          internal;
          include  /etc/nginx/mime.types;
          sub_filter '/api' '/flower/api';
          sub_filter "'/monitor" "'/flower/monitor";
          sub_filter "'/worker" "'/flower/worker";
          sub_filter "'/'" "'/flower/'";
          sub_filter "'/dashboard" "'/flower/dashboard";
          sub_filter '"/update-dashboard"' '"/flower/update-dashboard"';
          sub_filter_types application/javascript;  # by default, sub_filter won't touch JS
          sub_filter_last_modified on;
          sub_filter_once off;
          rewrite ^/flower-internal/static/(.*)$ /$1 break;
          root <PATH_TO_PYTHON/VENV_DIR>/site-packages/flower/static/;
          add_header Content-Type text/css;
        }

        location /flower-internal/ {
            internal;
            rewrite ^/flower-internal/(.*)$ /$1 break;
            sub_filter '="/' '="/flower/';
            sub_filter_last_modified on;
            sub_filter_once off;

            proxy_pass http://127.0.0.1:5555;
            proxy_set_header Host $host;
        }

And put this view under /flower/ in your urls.conf

@user_passes_test(lambda u: u.is_staff and u.is_superuser)
def flower_view(request):
    '''passes the request back up to nginx for internal routing'''
    response = HttpResponse()
    path = request.get_full_path()
    path = path.replace('flower', 'flower-internal', 1)
    response['X-Accel-Redirect'] = path
    return response

Then all you need to do is daemonize the celery flower server and have it listen to port 5555 (I use supervisor for this)

All 8 comments

I came here looking for exactly this issue. Exposing flower data through the Django admin would be really useful. I'm not using flower at present as it complicates things infrastructurally. If it were just another Django app, it'd really simplify things for a lot of people.

After looking through Flower's internals, and seeing the vastly different architecture Flower uses compared to Django, I'm assuming the answer to my question is "no".

However, I found the methods in the Celery package used by Flower, and I ended up calling these myself from Django to effectively get the same functionality.

Thanks for looking further into it, @chrisspen. Did you end up with anything worth sharing?

@lukeburden I followed what's basically outlined here. The only difference for Django is that, instead of just importing celery, you have to import the custom celery module you created in the root of your Django project, as outlined in Celery's Django tutorial docs.

just an idea, but do you think you could skip the configuring flower with apache/nginx and create a django view which requires whatever privileges you want and embeds flower using an iframe for localhost:5555. I haven't thought this through too much, but I figure this way flower wouldn't be exposed to the outside world and would be protected by Django's privilege system, right?

If you have nginx in front of django, you can add this to your nginx config

        location /flower-internal/static/ {
          internal;
          include  /etc/nginx/mime.types;
          sub_filter '/api' '/flower/api';
          sub_filter "'/monitor" "'/flower/monitor";
          sub_filter "'/worker" "'/flower/worker";
          sub_filter "'/'" "'/flower/'";
          sub_filter "'/dashboard" "'/flower/dashboard";
          sub_filter '"/update-dashboard"' '"/flower/update-dashboard"';
          sub_filter_types application/javascript;  # by default, sub_filter won't touch JS
          sub_filter_last_modified on;
          sub_filter_once off;
          rewrite ^/flower-internal/static/(.*)$ /$1 break;
          root <PATH_TO_PYTHON/VENV_DIR>/site-packages/flower/static/;
          add_header Content-Type text/css;
        }

        location /flower-internal/ {
            internal;
            rewrite ^/flower-internal/(.*)$ /$1 break;
            sub_filter '="/' '="/flower/';
            sub_filter_last_modified on;
            sub_filter_once off;

            proxy_pass http://127.0.0.1:5555;
            proxy_set_header Host $host;
        }

And put this view under /flower/ in your urls.conf

@user_passes_test(lambda u: u.is_staff and u.is_superuser)
def flower_view(request):
    '''passes the request back up to nginx for internal routing'''
    response = HttpResponse()
    path = request.get_full_path()
    path = path.replace('flower', 'flower-internal', 1)
    response['X-Accel-Redirect'] = path
    return response

Then all you need to do is daemonize the celery flower server and have it listen to port 5555 (I use supervisor for this)

Thanks @rgegriff for sharing your workaround!

flower is not a django app. It is implemented using tornado framework therefore it is not possible to embed it in django directly.

Here is my solution using proxy in Django https://stackoverflow.com/a/61997024/1763888.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Joe-Heffer-Shef picture Joe-Heffer-Shef  路  4Comments

hland picture hland  路  3Comments

davschne picture davschne  路  6Comments

jobec picture jobec  路  3Comments

kkzxak47 picture kkzxak47  路  8Comments