Веб-приложения обычно начинаются с простого, но могут стать довольно сложными, и большинство из них быстро перестают отвечать только за ответы на HTTP-запросы.
Когда это происходит, нужно проводить различие между тем, что должно происходить мгновенно (обычно в жизненном цикле HTTP-запроса), и тем, что может произойти в конце концов. Это почему? Ну, потому что, когда ваше приложение перегружено трафиком, простые вещи, подобные этому, имеют значение.
Операции в веб-приложении можно классифицировать как критические операции или операции времени запроса и фоновые задачи, которые выполняются вне времени запроса. Они соответствуют описанным выше:
- должно произойти мгновенно: операции времени запроса
- должно произойти в конце концов: фоновые задачи
Операции времени запроса могут выполняться в одном цикле запрос / ответ, не беспокоясь о том, что время ожидания истечет или что у пользователя могут возникнуть проблемы. Типичные примеры включают операции с базой данных CRUD (создание, чтение, обновление, удаление) и управление пользователями (процедуры входа / выхода из системы).
Фоновые задачи различаются, так как они обычно занимают много времени и подвержены сбоям, в основном из-за внешних зависимостей. Некоторые общие сценарии среди сложных веб-приложений включают в себя:
- отправка писем с подтверждением или активностью
- ежедневно сканирует и копирует информацию из разных источников и хранит их
- выполнение анализа данных
- удаление ненужных ресурсов
- экспорт документов / фотографий в различные форматы
Фоновые задачи являются основной целью этого урока. Наиболее распространенным шаблоном программирования, используемым для этого сценария, является Producer Consumer Architecture.
Проще говоря, эту архитектуру можно описать так:
- Производители создают данные или задачи.
- Задачи помещаются в очередь, которая называется очередью задач.
- Потребители несут ответственность за использование данных или выполнение задач.
Обычно потребители извлекают задачи из очереди по принципу «первым пришел — первым вышел» (FIFO) или в соответствии со своими приоритетами. Потребителей также называют рабочими, и этот термин мы будем использовать повсюду, поскольку он соответствует терминологии, используемой обсуждаемыми технологиями.
Какие задачи можно обрабатывать в фоновом режиме? Задачи, которые:
- не важны для базовой функциональности веб-приложения
- не может быть запущен в цикле запрос / ответ, так как они медленные (интенсивный ввод-вывод и т. д.)
- зависит от внешних ресурсов, которые могут быть недоступны или работать не так, как ожидалось
- возможно, потребуется повторить попытку хотя бы один раз
- должны быть выполнены по графику
Сельдерей является де-факто выбором для выполнения фоновых задач в экосистеме Python / Django. Он имеет простой и понятный API и прекрасно интегрируется с Django. Он поддерживает различные технологии для очереди задач и различные парадигмы для рабочих.
В этом уроке мы собираемся создать игрушечное веб-приложение Django (работающее со сценариями реального мира), которое использует фоновую обработку задач.
Настройка вещей
Предполагая, что вы уже знакомы с управлением пакетами Python и виртуальными средами, давайте установим Django:
1
|
$ pip install Django
|
Я решил создать еще одно приложение для блогов. В центре внимания приложения будет простота. Пользователь может просто создать учетную запись и без лишних хлопот может создать сообщение и опубликовать его на платформе.
Настройте quick_publisher
Django quick_publisher
:
1
|
$ django-admin startproject quick_publisher
|
Давайте запустим приложение:
1
2
|
$ cd quick_publisher
$ ./manage.py startapp main
|
При запуске нового проекта Django мне нравится создавать main
приложение, которое содержит, помимо прочего, пользовательскую модель пользователя. Чаще всего я сталкиваюсь с ограничениями модели Django User
по умолчанию. Наличие User
модели User
дает нам преимущество гибкости.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
# main/models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
class UserAccountManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
if not email:
raise ValueError(‘Email address must be provided’)
if not password:
raise ValueError(‘Password must be provided’)
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email=None, password=None, **extra_fields):
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields[‘is_staff’] = True
extra_fields[‘is_superuser’] = True
return self._create_user(email, password, **extra_fields)
class User(AbstractBaseUser, PermissionsMixin):
REQUIRED_FIELDS = []
USERNAME_FIELD = ’email’
objects = UserAccountManager()
email = models.EmailField(’email’, unique=True, blank=False, null=False)
full_name = models.CharField(‘full name’, blank=True, null=True, max_length=400)
is_staff = models.BooleanField(‘staff status’, default=False)
is_active = models.BooleanField(‘active’, default=True)
def get_short_name(self):
return self.email
def get_full_name(self):
return self.email
def __unicode__(self):
return self.email
|
Обязательно ознакомьтесь с документацией по Django, если вы не знакомы с работой пользовательских моделей.
Теперь нам нужно указать Django использовать эту модель пользователя вместо модели по умолчанию. Добавьте эту строку в файл quick_publisher/settings.py
:
AUTH_USER_MODEL = 'main.User'
Нам также нужно добавить main
приложение в список INSTALLED_APPS
в quick_publisher/settings.py
. Теперь мы можем создать миграции, применить их и создать суперпользователя, чтобы иметь возможность войти в админ-панель Django:
1
2
3
|
$ ./manage.py makemigrations main
$ ./manage.py migrate
$ ./manage.py createsuperuser
|
Давайте теперь создадим отдельное приложение Django, которое отвечает за сообщения:
1
|
$ ./manage.py startapp publish
|
Давайте определим простую модель Post в publisher/models.py
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
from django.db import models
from django.utils import timezone
from django.contrib.auth import get_user_model
class Post(models.Model):
author = models.ForeignKey(get_user_model())
created = models.DateTimeField(‘Created Date’, default=timezone.now)
title = models.CharField(‘Title’, max_length=200)
content = models.TextField(‘Content’)
slug = models.SlugField(‘Slug’)
def __str__(self):
return ‘»%s» by %s’ % (self.title, self.author)
|
Подключение модели Post
с помощью администратора Django выполняется в файле publisher/admin.py
следующим образом:
1
2
3
4
5
6
7
|
from django.contrib import admin
from .models import Post
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
pass
|
Наконец, давайте подключим приложение publisher
к нашему проекту, добавив его в список INSTALLED_APPS
.
Теперь мы можем запустить сервер и перейти на http://localhost:8000/admin/
и создать наши первые посты, чтобы у нас было что поиграть:
1
|
$ ./manage.py runserver
|
Я надеюсь, что вы сделали свою домашнюю работу и создали сообщения.
Давайте двигаться дальше. Следующий очевидный шаг — создать способ просмотра опубликованных постов.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
# publisher/views.py
from django.http import Http404
from django.shortcuts import render
from .models import Post
def view_post(request, slug):
try:
post = Post.objects.get(slug=slug)
except Post.DoesNotExist:
raise Http404(«Poll does not exist»)
return render(request, ‘post.html’, context={‘post’: post})
|
Давайте quick_publisher/urls.py
наш новый вид с URL в: quick_publisher/urls.py
01
02
03
04
05
06
07
08
09
10
11
|
# quick_publisher/urls.py
from django.conf.urls import url
from django.contrib import admin
from publisher.views import view_post
urlpatterns = [
url(r’^admin/’, admin.site.urls),
url(r’^(?P<slug>[a-zA-Z0-9\-]+)’, view_post, name=’view_post’)
]
|
Наконец, давайте создадим шаблон, который отображает сообщение в: publisher/templates/post.html
01
02
03
04
05
06
07
08
09
10
11
12
|
<!DOCTYPE html>
<html>
<head lang=»en»>
<meta charset=»UTF-8″>
<title></title>
</head>
<body>
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
<p>Published by {{ post.author.full_name }} on {{ post.created }}</p>
</body>
</html>
|
Теперь мы можем перейти в http: // localhost: 8000 / the-slug-of-the-post-you-созданный / в браузере. Это не совсем чудо веб-дизайна, но создание красивых постов выходит за рамки этого урока.
Отправка письма с подтверждением
Вот классический сценарий:
- Вы создаете учетную запись на платформе.
- Вы предоставляете адрес электронной почты для уникальной идентификации на платформе.
- Платформа проверяет, действительно ли вы являетесь владельцем адреса электронной почты, отправив письмо со ссылкой для подтверждения.
- Пока вы не выполните проверку, вы не сможете (полностью) использовать платформу.
Давайте добавим флаг is_verified
и is_verified
модели User
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
# main/models.py
import uuid
class User(AbstractBaseUser, PermissionsMixin):
REQUIRED_FIELDS = []
USERNAME_FIELD = ’email’
objects = UserAccountManager()
email = models.EmailField(’email’, unique=True, blank=False, null=False)
full_name = models.CharField(‘full name’, blank=True, null=True, max_length=400)
is_staff = models.BooleanField(‘staff status’, default=False)
is_active = models.BooleanField(‘active’, default=True)
is_verified = models.BooleanField(‘verified’, default=False) # Add the `is_verified` flag
verification_uuid = models.UUIDField(‘Unique Verification UUID’, default=uuid.uuid4)
def get_short_name(self):
return self.email
def get_full_name(self):
return self.email
def __unicode__(self):
return self.email
|
Давайте воспользуемся этим случаем, чтобы добавить модель User к администратору:
1
2
3
4
5
6
7
|
from django.contrib import admin
from .models import User
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
pass
|
Давайте внесем изменения в базу данных:
1
2
|
$ ./manage.py makemigrations
$ ./manage.py migrate
|
Теперь нам нужно написать кусок кода, который отправляет электронное письмо при создании пользовательского экземпляра. Это то, для чего нужны сигналы Django, и это прекрасный повод затронуть эту тему.
Сигналы запускаются до / после определенных событий в приложении. Мы можем определить функции обратного вызова, которые запускаются автоматически при срабатывании сигналов. Чтобы сделать триггер обратного вызова, мы должны сначала подключить его к сигналу.
Мы собираемся создать обратный вызов, который будет запущен после создания пользовательской модели. Мы добавим этот код после определения модели User
в: main/models.py
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
from django.db.models import signals
from django.core.mail import send_mail
def user_post_save(sender, instance, signal, *args, **kwargs):
if not instance.is_verified:
# Send verification email
send_mail(
‘Verify your QuickPublisher account’,
‘Follow this link to verify your account: ‘
‘http://localhost:8000%s’ % reverse(‘verify’, kwargs={‘uuid’: str(instance.verification_uuid)}),
[instance.email],
fail_silently=False,
)
signals.post_save.connect(user_post_save, sender=User)
|
Что мы сделали здесь, так это то, что мы определили функцию user_post_save
и соединили ее с сигналом post_save
(тот, который срабатывает после сохранения модели), отправляемым моделью User
.
Джанго не просто отправляет электронные письма самостоятельно; это должно быть привязано к почтовому сервису. Для простоты вы можете добавить свои учетные данные Gmail в quick_publisher/settings.py
или добавить своего любимого почтового провайдера.
Вот как выглядит конфигурация Gmail:
1
2
3
4
5
|
EMAIL_USE_TLS = True
EMAIL_HOST = ‘smtp.gmail.com’
EMAIL_HOST_USER = ‘<YOUR_GMAIL_USERNAME>@gmail.com’
EMAIL_HOST_PASSWORD = ‘<YOUR_GMAIL_PASSWORD>’
EMAIL_PORT = 587
|
Чтобы проверить это, зайдите в панель администратора и создайте нового пользователя с действительным адресом электронной почты, который вы можете быстро проверить. Если все прошло хорошо, вы получите письмо со ссылкой для подтверждения. Процедура проверки еще не готова.
Вот как проверить аккаунт:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
# main/views.py
from django.http import Http404
from django.shortcuts import render, redirect
from .models import User
def home(request):
return render(request, ‘home.html’)
def verify(request, uuid):
try:
user = User.objects.get(verification_uuid=uuid, is_verified=False)
except User.DoesNotExist:
raise Http404(«User does not exist or is already verified»)
user.is_verified = True
user.save()
return redirect(‘home’)
|
quick_publisher/urls.py
представления в: quick_publisher/urls.py
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
# quick_publisher/urls.py
from django.conf.urls import url
from django.contrib import admin
from publisher.views import view_post
from main.views import home, verify
urlpatterns = [
url(r’^$’, home, name=’home’),
url(r’^admin/’, admin.site.urls),
url(r’^verify/(?P<uuid>[a-z0-9\-]+)/’, verify, name=’verify’),
url(r’^(?P<slug>[a-zA-Z0-9\-]+)’, view_post, name=’view_post’)
]
|
Также не забудьте создать файл home.html
в main/templates/home.html
. Это будет предоставлено home
видом.
Попробуйте запустить весь сценарий снова и снова. Если все в порядке, вы получите электронное письмо с действительным проверочным URL. Если вы перейдете по URL-адресу, а затем зарегистрируетесь у администратора, вы увидите, как была проверена учетная запись.
Отправка писем асинхронно
Вот проблема с тем, что мы сделали до сих пор. Возможно, вы заметили, что создание пользователя немного медленно. Это потому, что Django отправляет письмо с подтверждением в течение времени запроса.
Вот как это работает: мы отправляем пользовательские данные в приложение Django. Приложение создает модель User
а затем создает соединение с Gmail (или другой выбранной вами службой). Django ждет ответа и только потом возвращает ответ нашему браузеру.
Вот где приходит Celery. Сначала убедитесь, что он установлен:
1
|
$ pip install Celery
|
Теперь нам нужно создать приложение Celery в нашем приложении Django:
01
02
03
04
05
06
07
08
09
10
11
12
|
# quick_publisher/celery.py
import os
from celery import Celery
os.environ.setdefault(‘DJANGO_SETTINGS_MODULE’, ‘quick_publisher.settings’)
app = Celery(‘quick_publisher’)
app.config_from_object(‘django.conf:settings’)
# Load task modules from all registered Django app configs.
app.autodiscover_tasks()
|
Сельдерей — это очередь задач. Он получает задачи из нашего приложения Django и запускает их в фоновом режиме. Сельдерей должен быть в паре с другими службами, которые действуют как брокеры.
Брокеры занимаются промежуточной отправкой сообщений между веб-приложением и Celery. В этом уроке мы будем использовать Redis. Redis прост в установке, и мы можем легко начать с ним без особых хлопот.
Вы можете установить Redis, следуя инструкциям на странице быстрого запуска Redis. Вам нужно будет установить библиотеку Redis Python, pip install redis
и пакет, необходимый для использования Redis и Celery: pip install celery[redis]
.
Запустите сервер Redis в отдельной консоли, например: $ redis-server
Давайте добавим конфиги, связанные с quick_publisher/settings.py
Redis, в quick_publisher/settings.py
:
1
2
3
4
5
6
|
# REDIS related settings
REDIS_HOST = ‘localhost’
REDIS_PORT = ‘6379’
BROKER_URL = ‘redis://’ + REDIS_HOST + ‘:’ + REDIS_PORT + ‘/0’
BROKER_TRANSPORT_OPTIONS = {‘visibility_timeout’: 3600}
CELERY_RESULT_BACKEND = ‘redis://’ + REDIS_HOST + ‘:’ + REDIS_PORT + ‘/0’
|
Прежде чем что-либо запустить в Celery, оно должно быть объявлено как задание.
Вот как это сделать:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
# main/tasks.py
import logging
from django.urls import reverse
from django.core.mail import send_mail
from django.contrib.auth import get_user_model
from quick_publisher.celery import app
@app.task
def send_verification_email(user_id):
UserModel = get_user_model()
try:
user = UserModel.objects.get(pk=user_id)
send_mail(
‘Verify your QuickPublisher account’,
‘Follow this link to verify your account: ‘
‘http://localhost:8000%s’ % reverse(‘verify’, kwargs={‘uuid’: str(user.verification_uuid)}),
[user.email],
fail_silently=False,
)
except UserModel.DoesNotExist:
logging.warning(«Tried to send verification email to non-existing user ‘%s'» % user_id)
|
Здесь мы сделали следующее: мы переместили функцию отправки письма с подтверждением в другой файл с именем tasks.py
.
Несколько заметок:
- Имя файла важно. Celery просматривает все приложения в
INSTALLED_APPS
и регистрирует задачи в файлахtasks.py
. - Обратите внимание, как мы украсили функцию
send_verification_email
с помощью@app.task
. Это говорит Celery, что это задача, которая будет выполняться в очереди задач. - Обратите внимание, что мы ожидаем в качестве аргумента
user_id
а не объектаUser
. Это связано с тем, что при отправке задач в Celery у нас могут возникнуть проблемы с сериализацией сложных объектов. Лучше держать их простыми.
Возвращаясь к main/models.py
, код сигнала превращается в:
01
02
03
04
05
06
07
08
09
10
|
from django.db.models import signals
from main.tasks import send_verification_email
def user_post_save(sender, instance, signal, *args, **kwargs):
if not instance.is_verified:
# Send verification email
send_verification_email.delay(instance.pk)
signals.post_save.connect(user_post_save, sender=User)
|
Обратите внимание, как мы вызываем метод .delay
для объекта задачи. Это означает, что мы отправляем задачу в Celery и не ждем результата. Если бы вместо этого мы использовали send_verification_email(instance.pk)
, мы все равно отправили бы его в Celery, но ожидали бы завершения задачи, а это не то, что нам нужно.
Прежде чем вы начнете создавать нового пользователя, есть одна загвоздка. Сельдерей — это услуга, и нам нужно ее запустить. Откройте новую консоль, убедитесь, что вы активировали соответствующий virtualenv, и перейдите в папку проекта.
1
|
$ celery worker -A quick_publisher —loglevel=debug —concurrency=4
|
Это запускает четырех рабочих из сельдерея. Да, теперь вы можете, наконец, пойти и создать другого пользователя. Обратите внимание, что задержки нет, и обязательно просмотрите журналы в консоли Celery и посмотрите, правильно ли выполняются задачи. Это должно выглядеть примерно так:
1
2
|
[2017-04-28 15:00:09,190: DEBUG/MainProcess] Task accepted: main.tasks.send_verification_email[f1f41e1f-ca39-43d2-a37d-9de085dc99de] pid:62065
[2017-04-28 15:00:11,740: INFO/PoolWorker-2] Task main.tasks.send_verification_email[f1f41e1f-ca39-43d2-a37d-9de085dc99de] succeeded in 2.5500912349671125s: None
|
Периодические Задачи С Сельдереем
Вот еще один распространенный сценарий. Большинство зрелых веб-приложений отправляют своим пользователям электронные письма в течение всего жизненного цикла, чтобы поддерживать их заинтересованность. Некоторые распространенные примеры писем о жизненном цикле:
- ежемесячные отчеты
- уведомления об активности (лайки, запросы дружбы и т. д.)
- напоминания для выполнения определенных действий («Не забудьте активировать свой аккаунт»)
Вот что мы собираемся сделать в нашем приложении. Мы собираемся посчитать, сколько раз каждое сообщение было просмотрено, и отправить ежедневный отчет автору. Раз в день мы собираемся просмотреть всех пользователей, получить их сообщения и отправить электронное письмо с таблицей, содержащей сообщения и количество просмотров.
Давайте изменим модель Post
чтобы мы могли учесть сценарий количества просмотров.
01
02
03
04
05
06
07
08
09
10
|
class Post(models.Model):
author = models.ForeignKey(User)
created = models.DateTimeField(‘Created Date’, default=timezone.now)
title = models.CharField(‘Title’, max_length=200)
content = models.TextField(‘Content’)
slug = models.SlugField(‘Slug’)
view_count = models.IntegerField(«View Count», default=0)
def __str__(self):
return ‘»%s» by %s’ % (self.title, self.author)
|
Как всегда, когда мы меняем модель, нам нужно перенести базу данных:
1
2
3
|
$ ./manage.py makemigrations
$ ./manage.py migrate
|
Давайте также view_post
представление view_post
Django для подсчета просмотров:
01
02
03
04
05
06
07
08
09
10
|
def view_post(request, slug):
try:
post = Post.objects.get(slug=slug)
except Post.DoesNotExist:
raise Http404(«Poll does not exist»)
post.view_count += 1
post.save()
return render(request, ‘post.html’, context={‘post’: post})
|
Было бы полезно отобразить view_count
в шаблоне. Добавьте этот <p>Viewed {{ post.view_count }} times</p>
где-нибудь внутри файла publisher/templates/post.html
. Сделайте несколько просмотров поста и посмотрите, как увеличивается счетчик.
Давайте создадим задачу Celery. Поскольку речь идет о постах, я собираюсь разместить их в publisher/tasks.py
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
from django.template import Template, Context
from django.core.mail import send_mail
from django.contrib.auth import get_user_model
from quick_publisher.celery import app
from publisher.models import Post
REPORT_TEMPLATE = «»»
Here’s how you did till now:
{% for post in posts %}
«{{ post.title }}»: viewed {{ post.view_count }} times |
{% endfor %}
«»»
@app.task
def send_view_count_report():
for user in get_user_model().objects.all():
posts = Post.objects.filter(author=user)
if not posts:
continue
template = Template(REPORT_TEMPLATE)
send_mail(
‘Your QuickPublisher Activity’,
template.render(context=Context({‘posts’: posts})),
[user.email],
fail_silently=False,
)
|
Каждый раз, когда вы вносите изменения в задачи Celery, не забудьте перезапустить процесс Celery. Сельдерей должен обнаружить и перезагрузить задачи. Перед созданием периодической задачи мы должны проверить это в оболочке Django, чтобы убедиться, что все работает как задумано:
1
2
3
4
5
|
$ ./manage.py shell
In [1]: from publisher.tasks import send_view_count_report
In [2]: send_view_count_report.delay()
|
Надеюсь, вы получили отличный маленький отчет в своем электронном письме.
Давайте теперь создадим периодическое задание. Откройте quick_publisher/celery.py
и зарегистрируйте периодические задачи:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
# quick_publisher/celery.py
import os
from celery import Celery
from celery.schedules import crontab
os.environ.setdefault(‘DJANGO_SETTINGS_MODULE’, ‘quick_publisher.settings’)
app = Celery(‘quick_publisher’)
app.config_from_object(‘django.conf:settings’)
# Load task modules from all registered Django app configs.
app.autodiscover_tasks()
app.conf.beat_schedule = {
‘send-report-every-single-minute’: {
‘task’: ‘publisher.tasks.send_view_count_report’,
‘schedule’: crontab(), # change to `crontab(minute=0, hour=0)` if you want it to run daily at midnight
},
}
|
Пока что мы создали расписание, которое будет запускать задачу publisher.tasks.send_view_count_report
каждую минуту, как указано в записи crontab()
. Вы также можете указать различные графики сельдерея Crontab .
Откройте другую консоль, активируйте соответствующую среду и запустите службу Celery Beat.
1
|
$ celery -A quick_publisher beat
|
Работа сервиса Beat заключается в том, чтобы продвигать задания в сельдерее в соответствии с графиком. Примите во внимание, что расписание заставляет задачу send_view_count_report
запускаться каждую минуту в соответствии с настройкой. Это хорошо для тестирования, но не рекомендуется для реального веб-приложения.
Делая задачи более надежными
Задачи часто используются для выполнения ненадежных операций, операций, которые зависят от внешних ресурсов или которые могут легко завершиться неудачей по различным причинам. Вот руководство для того, чтобы сделать их более надежными:
- Сделать задачи идемпотентными. Идемпотентная задача — это задача, которая, если ее остановить на полпути, никак не изменит состояния системы. Задача либо полностью вносит изменения в систему, либо вообще не вносит изменений.
- Повторите задачи. Если задача не выполняется, рекомендуется попробовать ее снова и снова, пока она не будет выполнена успешно. Вы можете сделать это в сельдерее с помощью сельдерея . Еще одна интересная вещь — алгоритм экспоненциального отката . Это может пригодиться, если вы думаете об ограничении ненужной нагрузки на сервер из-за повторных попыток.
Выводы
Я надеюсь, что это был интересный учебник для вас и хорошее введение в использование Celery с Django.
Вот несколько выводов, которые мы можем сделать:
- Рекомендуется оставлять ненадежные и трудоемкие задачи вне времени запроса.
- Долгосрочные задачи должны выполняться в фоновом режиме рабочими процессами (или другими парадигмами).
- Фоновые задачи могут использоваться для различных задач, которые не являются критическими для основного функционирования приложения.
- Сельдерей может также справляться с периодическими задачами, используя сервис
celery beat
. - Задачи могут быть более надежными, если их сделать идемпотентными и повторить (возможно, с использованием экспоненциального отката).