Django База [2023]: Резервная копия базы данных по расписанию - пользовательская команда с Celery Beat 🛡️ #46
Django

Django База [2023]: Резервная копия базы данных по расписанию - пользовательская команда с Celery Beat 🛡️ #46

Razilator

Резервная копия базы данных является критически важным аспектом обеспечения безопасности и целостности данных. Регулярное создание резервных копий поможет защитить ваши данные от случайных или злонамеренных ошибок.

В этой статье мы рассмотрим, как создать резервную копию базы данных в Django с помощью собственной команды и расписания Celery Beat.

Создание собственной команды для резервной копии базы данных в Django

В нашем модуле services (создавали в этом уроке) с вспомогающим функционалом для Django, создадим папку management, в ней папку commands, а внутри commands два файла: init.py и dbackup.py.

Структура папок должна получиться следующая:

modules/services/management/commands/dbackup.py
modules/services/management/commands/dbackup.py

Далее пишем код работы резервного копирования по команде в созданном файле dbackup.py:

services/management/commands/dbackup.py
from django.core.management import BaseCommand
from django.core.management import call_command
from datetime import datetime

class Command(BaseCommand):
    """
    Команда для создания резервной копии базы данных
    """
    def handle(self, *args, **options):
        self.stdout.write('Waiting for database dump...')
        call_command(
            'dumpdata', 
            '--natural-foreign', 
            '--natural-primary', 
            '--exclude=contenttypes', 
            '--exclude=admin.logentry', 
            '--indent=4', 
            f'--output=database-{datetime.now().strftime("%Y-%m-%d-%H-%M-%S")}.json'
        )
        self.stdout.write(self.style.SUCCESS('Database successfully backed up'))

Этот код - это пользовательская команда Django, которая выполняет резервное копирование базы данных в формате JSON, используя команду Django dumpdata.

Файл BaseCommand из модуля django.core.management является базовым классом для создания пользовательских команд Django. Он определяет структуру, которую нужно использовать для создания собственной команды.

handle() является обязательным методом для всех пользовательских команд Django, он вызывается при запуске команды.

call_command() - это встроенная функция Django, которая вызывает другие команды Django. В данном случае мы используем call_command() для вызова команды dumpdata с параметрами, которые указывают какие модели исключить из дампа.

В параметре f'--output=database-{datetime.now().strftime("%Y-%m-%d-%H-%M-%S")}.json' мы указываем имя файла для выходного JSON-файла, включая дату и время создания файла.

Метод self.stdout.write() используется для вывода информации на стандартный вывод командной строки. После успешного создания резервной копии базы данных метод self.stdout.write() выводит сообщение об успехе, используя self.style.SUCCESS(), который форматирует вывод в зеленый цвет для удобства чтения.

Добавление команды в список задач Celery

Откроем файл tasks.py из нашего модуля services, и добавим новую задачу для Celery:

services/tasks.py
from celery import shared_task
from django.core.management import call_command

from .email import send_activate_email_message, send_contact_email_message


@shared_task
def send_activate_email_message_task(user_id):
    """
    1. Задача обрабатывается в представлении: UserRegisterView
    2. Отправка письма подтверждения осуществляется через функцию: send_activate_email_message
    """
    return send_activate_email_message(user_id)


@shared_task
def send_contact_email_message_task(subject, email, content, ip, user_id):
    """
    1. Задача обрабатывается в представлении: FeedbackCreateView
    2. Отправка письма из формы обратной связи осуществляется через функцию: send_contact_email_message
    """
    return send_contact_email_message(subject, email, content, ip, user_id)


@shared_task()
def dbackup_task():
    """
    Выполнение резервного копирования базы данных
    """
    call_command('dbackup')

Отлично. Команду добавили. Далее необходимо установить Celery Beat.

Установка и настройка Celery Beat

Celery Beat - это компонент Celery, который отвечает за периодическое выполнение задач в фоновом режиме. Установим этот компонент с помощью следующей команды: pip install django-celery-beat

Внимание: перед установкой Celery Beat, вы должны настроить Celery и Redis из этой статьи.

Для того, чтобы наша задача резервного копирования выполнялась по расписанию, нам необходимо добавить соответствующую запись в конфигурационный файл settings.py нашего проекта. Не забываем импортировать в начало файла рядом с другими импортами from celery.schedules import crontab.

backend/settings.py
from pathlib import Path
from celery.schedules import crontab # Рядом с другими импортами

# Celery settings

CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
CELERY_TASK_TRACK_STARTED = True
CELERY_TASK_TIME_LIMIT = 30 * 60
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TASK_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Europe/Moscow'

CELERY_BEAT_SCHEDULE = {
    'backup_database': {
        'task': 'modules.services.tasks.dbackup_task', # Путь к задаче указанной в tasks.py
        'schedule': crontab(hour=0, minute=0),  # Резервная копия будет создаваться каждый день в полночь
    },
}

Этот код добавляет задачу резервного копирования базы данных, которая будет выполняться каждый день в полночь.

Обратите внимание, что в этом коде мы использовали функцию crontab() из библиотеки Celery Beat для определения расписания задачи. Эта функция позволяет нам указать расписание задачи в формате cron, который используется в Linux и других UNIX-подобных системах для периодического запуска задач.

Запуск Celery и Celery Beat вместе

Теперь мы настроили всё, что нам необходимо.

Далее нам нужно запустить Celery в два процесса, один с worker, другой с beat.

Worker отвечает за обработку задач в очереди, а Beat отвечает за планирование задач по расписанию. Они должны быть запущены в отдельных процессах. Обычно для этого используется два терминала, в каждом из которых запускается свой процесс.

Для запуска worker'а используется команда: celery --app=backend worker --loglevel=info --pool=solo

Для запуска beat'а: celery -A backend beat -l info

Также можно запустить оба процесса одной командой, используя флаг -B (Не работает на Windows): celery -A backend worker -B -l info

Флаг -B включает beat. Однако, если worker и beat работают в одном процессе, то может возникнуть проблема с утечкой памяти, поэтому лучше запускать их в отдельных процессах.

Проверка работы Celery и Celery Beat с задачей

Запустив Django, Celery и Celery Beat, я получил резервную копию в фоновом режиме в назначенное время.

Взаимодействие Celery Beat и Celery, сохраненная база данных
Взаимодействие Celery Beat и Celery, сохраненная база данных
;