Skip to main content

Drop in, configurable, dependency-free progress bars for your Django/Celery applications.

Project description

Celery Progress Bars for Django

Drop in, dependency-free progress bars for your Django/Celery applications.

Super simple setup. Lots of customization available.

Demo

Celery Progress Bar demo on SaaS Pegasus

Github demo application: build a download progress bar for Django

Starting with Celery can be challenging, eeintech built a complete Django demo application along with a step-by-step guide to get you started on building your own progress bar!

Installation

If you haven't already, make sure you have properly set up celery in your project.

Then install this library:

pip install celery-progress

Usage

Prerequisites

First add celery_progress to your INSTALLED_APPS in settings.py.

Then add the following url config to your main urls.py:

from django.urls import path, include

urlpatterns = [
    # your project's patterns here
    ...
    path(r'^celery-progress/', include('celery_progress.urls')),  # add this line (the endpoint is configurable)
]   

Recording Progress

In your task you should add something like this:

from celery import shared_task
from celery_progress.backend import ProgressRecorder
import time

@shared_task(bind=True)
def my_task(self, seconds):
    progress_recorder = ProgressRecorder(self)
    result = 0
    for i in range(seconds):
        time.sleep(1)
        result += i
        progress_recorder.set_progress(i + 1, seconds)
    return result

You can add an optional progress description like this:

  progress_recorder.set_progress(i + 1, seconds, description='my progress description')

Displaying progress

In the view where you call the task you need to get the task ID like so:

views.py

def progress_view(request):
    result = my_task.delay(10)
    return render(request, 'display_progress.html', context={'task_id': result.task_id})

Then in the page you want to show the progress bar you just do the following.

Add the following HTML wherever you want your progress bar to appear:

display_progress.html

<div class='progress-wrapper'>
  <div id='progress-bar' class='progress-bar' style="background-color: #68a9ef; width: 0%;">&nbsp;</div>
</div>
<div id="progress-bar-message">Waiting for progress to start...</div>

Import the javascript file.

display_progress.html

<script src="{% static 'celery_progress/celery_progress.js' %}"></script>

Initialize the progress bar:

// vanilla JS version
document.addEventListener("DOMContentLoaded", function () {
  var progressUrl = "{% url 'celery_progress:task_status' task_id %}";
  CeleryProgressBar.initProgressBar(progressUrl);
});

or

// JQuery
$(function () {
  var progressUrl = "{% url 'celery_progress:task_status' task_id %}";
  CeleryProgressBar.initProgressBar(progressUrl)
});

Displaying the result of a task

If you'd like you can also display the result of your task on the front end.

To do that follow the steps below. Result handling can also be customized.

Initialize the result block:

This is all that's needed to render the result on the page.

display_progress.html

<div id="celery-result"></div>

But more likely you will want to customize how the result looks, which can be done as below:

// JQuery
var progressUrl = "{% url 'celery_progress:task_status' task_id %}";

function customResult(resultElement, result) {
  $( resultElement ).append(
    $('<p>').text('Sum of all seconds is ' + result)
  );
}

$(function () {
  CeleryProgressBar.initProgressBar(progressUrl, {
    onResult: customResult,
  })
});

Working with Groups

This library includes experimental support for working with Celery groups. You can use the "group_status" URL endpoint for this. Here is a basic example:

Example task:

@shared_task(bind=True)
def add(self, x, y):
    return x + y

Calling view:

from celery import group
from .tasks import add

def progress_view(request):
    task_group = group(add.s(i, i) for i in range(100))
    group_result = task_group.apply_async()
    # you must explicitly call the save function on the group_result after calling the tasks
    group_result.save()
    return render(request, 'display_progress.html', context={'task_id': group_result.id})

Template:

document.addEventListener("DOMContentLoaded", function () {
  var progressUrl = "{% url 'celery_progress:group_status' task_id %}";
  CeleryProgressBar.initProgressBar(progressUrl);
});

Customization

The initProgressBar function takes an optional object of options. The following options are supported:

Option What it does Default Value
pollInterval How frequently to poll for progress (in milliseconds) 500
progressBarId Override the ID used for the progress bar 'progress-bar'
progressBarMessageId Override the ID used for the progress bar message 'progress-bar-message'
progressBarElement Override the element used for the progress bar. If specified, progressBarId will be ignored. document.getElementById(progressBarId)
progressBarMessageElement Override the element used for the progress bar message. If specified, progressBarMessageId will be ignored. document.getElementById(progressBarMessageId)
resultElementId Override the ID used for the result 'celery-result'
resultElement Override the element used for the result. If specified, resultElementId will be ignored. document.getElementById(resultElementId)
onProgress function to call when progress is updated onProgressDefault
onSuccess function to call when progress successfully completes onSuccessDefault
onError function to call on a known error with no specified handler onErrorDefault
onRetry function to call when a task attempts to retry onRetryDefault
onIgnored function to call when a task result is ignored onIgnoredDefault
onTaskError function to call when progress completes with an error onError
onNetworkError function to call on a network error (ignored by WebSocket) onError
onHttpError function to call on a non-200 response (ignored by WebSocket) onError
onDataError function to call on a response that's not JSON or has invalid schema due to a programming error onError
onResult function to call when returned non empty result CeleryProgressBar.onResultDefault
barColors dictionary containing color values for various progress bar states. Colors that are not specified will defer to defaults barColorsDefault
defaultMessages dictionary containing default messages that can be overridden see below

The barColors option allows you to customize the color of each progress bar state by passing a dictionary of key-value pairs of state: #hexcode. The defaults are shown below.

State Hex Code Image Color
success #76ce60 #76ce60
error #dc4f63 #dc4f63
progress #68a9ef #68a9ef
ignored #7a7a7a #7a7a7a

The defaultMessages option allows you to override some default messages in the UI. At the moment these are:

Message Id When Shown Default Value
waiting Task is waiting to start 'Waiting for task to start...'
started Task has started but reports no progress 'Task started...'

WebSocket Support

Additionally, this library offers WebSocket support using Django Channels courtesy of EJH2.

A working example project leveraging WebSockets is available here.

To use WebSockets, install with pip install celery-progress[websockets,redis] or pip install celery-progress[websockets,rabbitmq] (depending on broker dependencies).

See WebSocketProgressRecorder and websockets.js for details.

Securing the get_progress endpoint

By default, anyone can see the status and result of any task by accessing /celery-progress/<task_id>

To limit access, you need to wrap get_progress() in a view of your own which implements the permissions check, and create a new url routing to point to your view. Make sure to remove any existing (unprotected) celery progress urls from your root urlconf at the same time.

For example, requiring login with a class-based view:

# views.py
from celery_progress.views import get_progress
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import View

class TaskStatus(LoginRequiredMixin, View):
    def get(self, request, task_id, *args, **kwargs):
        # Other checks could go here
        return get_progress(request, task_id=task_id)
# urls.py
from django.urls import path
from . import views

urlpatterns = [
    ...
    path('task-status/<uuid:task_id>', views.TaskStatus.as_view(), name='task_status'),
    ...
]

Requiring login with a function-based view:

# views.py
from celery_progress.views import get_progress
from django.contrib.auth.decorators import login_required

@login_required
def task_status(request, task_id):
    # Other checks could go here
    return get_progress(request, task_id)
# urls.py
from django.urls import path

from . import views

urlpatterns = [
    ...
    path('task-status/<uuid:task_id>', views.task_status, name='task_status'),
    ...
]

Any links to 'celery_progress:task_status' will need to be changed to point to your new endpoint.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

celery_progress-0.4.tar.gz (15.9 kB view details)

Uploaded Source

Built Distribution

celery_progress-0.4-py3-none-any.whl (17.3 kB view details)

Uploaded Python 3

File details

Details for the file celery_progress-0.4.tar.gz.

File metadata

  • Download URL: celery_progress-0.4.tar.gz
  • Upload date:
  • Size: 15.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.0 CPython/3.11.9

File hashes

Hashes for celery_progress-0.4.tar.gz
Algorithm Hash digest
SHA256 0343a9a5111e1790c3b68fb5ce0b7889dd05b445e77e2f42469303acaea2ecbf
MD5 46d3f07150558af82cc1ac846865fb47
BLAKE2b-256 af3b5e6facf5cefbff0eb42ded0eead292d264204bf8d4ef8c9667859b54481b

See more details on using hashes here.

File details

Details for the file celery_progress-0.4-py3-none-any.whl.

File metadata

File hashes

Hashes for celery_progress-0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 7521b38a3160ef18b214c241810830698fa4734094d2819098256f83bc1c7a4d
MD5 b3d77e1b09c203cb17d793cd2302822b
BLAKE2b-256 ca248559dc0593b130ba8198c2bcdc8e809977fa84cce231add13b56244da1b3

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page