Как запустить функцию Python 3 даже после того, как пользователь закрыл веб-браузер/вкладку?

У меня возникла проблема с проектом Python, над которым я работаю (обычно я использую PHP/Java, поэтому мне не хватает знаний). По сути, у меня есть программа на Python, которую я создал с помощью Flask, которая подключает систему управления запасами к Shopify с помощью API Shopify Python.

Когда пользователь запускает функцию через запрос AJAX, мне нужно запустить функцию/процесс, который обновляет продукты в магазине Shopify клиента через Shopify API. Это занимает около 2 часов (примерно 7000 товаров плюс нужно сначала извлечь их из системы управления запасами). Проблема в том, что мне нужен способ запуска этой функции/процесса, и даже если клиент закроет свой браузер, функция/процесс продолжит работу.

Если есть какой-либо способ, которым я мог бы обновить внешний интерфейс с текущим ходом этой фоновой функции/процесса, это было бы здорово.

Если кто-нибудь знает о какой-либо библиотеке или ресурсах для этого, мы будем очень признательны. У меня был Google, но все решения, которые я могу найти, похоже, предназначены для сценариев CLI, а не для веб-скриптов.

Большое спасибо, Кори :)


person Fishingfon    schedule 14.05.2020    source источник
comment
Для этого можно использовать сельдерей. docs.celeryproject.org/en/stable   -  person Calumah    schedule 14.05.2020
comment
Вы не можете сделать это из браузера. Для этого у вас должен быть серверный сервис. См. ответ @GabrielCappelli (или любой последующий ответ). Для этого вы можете собрать части инфраструктуры в облаке — например. объединить облачную службу обмена сообщениями со службой облачных функций (лямбда).   -  person davidbak    schedule 18.05.2020


Ответы (2)


Вы должны обрабатывать эту задачу асинхронно, потому что это длительная работа, которая может значительно снизить производительность HTTP-ответа (если вы подождете, пока он не завершится).

Кроме того, вы можете заметить, что вам нужно запустить эту задачу в отдельном процессе текущего процесса, который обслуживает ваш HTTP-запрос. Потому что веб-серверы (Gunicorn, uWSGI и т. д.) будут порождать созданный ими процесс и освобождать системные ресурсы, когда им это нужно. Вы легко можете быть в том случае, если асинхронный процесс, запущенный через Ajax, будет прерван и убит веб-сервером, потому что вы закрыли браузер (запрос закрыт). Итак, threading и coroutines не самые лучшие инструменты для этой задачи.

Вот почему есть несколько классных Task queue проектов, которые решат вашу проблему. Мы можем отметить:

  • Celery: (готовое решение) это очередь задач с упором на обработку в реальном времени, а также поддерживает планирование задач. Хорошо работает с Redis и RabbitMQ в качестве брокеров сообщений.
  • RQ (Redis Queue): RQ (Redis Queue) — это простая библиотека Python для постановки заданий в очередь и их обработки в фон с рабочими. Он поддерживается Redis и имеет низкий барьер для входа. Его можно легко интегрировать в ваш веб-стек.
  • Taskmaster: Taskmaster – это простая распределенная очередь, предназначенная для обработки большого количества разовых задач.
  • Huey – это очередь задач на основе Redis, призванная обеспечить простую, но гибкую структуру. для выполнения задач. Huey поддерживает планирование задач, повторяющиеся задачи в стиле crontab, хранение результатов и автоматический повтор в случае сбоя.
  • Dramatiq: быстрая и надежная альтернатива Celery. Он поддерживает RabbitMQ и Redis в качестве брокеров сообщений.
  • APScheduler: расширенный планировщик Python (APScheduler) — это библиотека Python, позволяющая планировать выполнение кода Python. выполняться позже, однократно или периодически.

И многое другое!

А с появлением micro services вы можете объединить мощь Task queues и containers и создать отдельный контейнер (контейнеры), который будет обрабатывать ваши длительные задачи (и обновлять базу данных (базы данных) в соответствии с вашим текущим делом). Кроме того, если вы еще не можете использовать архитектуру micro services, вы можете создать отдельный сервер, который будет обрабатывать эти задачи, и освободить веб-сервер, который обрабатывает запросы пользователей, от выполнения длительных задач.

Наконец, вы можете комбинировать эти решения на своем текущем веб-сайте, как в этом сценарии:

  • Пользователь нажимает на кнопку.
  • Запрос Ajax запускает ваш бэкэнд (через API или что-то еще)
  • Вы планируете задачу в своем сообщении брокера, чтобы запустить ее сейчас или позже (в отдельном контейнере/VPS...)
  • В вашем бэкэнде вы получаете Task ID задачи
  • Вы возвращаете Task ID по API или как-то еще и добавляете его в файлы cookie сеанса или в отдельную таблицу, которая имеет дело с пользователем, запустившим процесс.
  • В некоторых JS вы продолжаете запрашивать статус задачи из своего бэкэнда с помощью Task ID, которые у вас есть (в файлах cookie сеанса пользователя или в вашей базе данных)
  • Даже если пользователь закроет свой браузер, задача продолжит свое действие до тех пор, пока не завершится или не вызовет исключение. И в рамках идентификатора задачи, который у вас уже есть, вы можете легко узнать статус этой задачи и отправить эту информацию пользователю (в представлении, когда он снова войдет в систему, по электронной почте и т. д.)

И, конечно же, вы можете улучшить этот сценарий!

person Chiheb Nexus    schedule 18.05.2020

Обычно вы создаете задачу и возвращаете пользователю идентификатор, который он может использовать для объединения статуса указанной задачи.

Затем вы обработаете задачу в другом контейнере\процессе\потоке.

Celery — это библиотека Python, которая может помочь вам настроить это.

Другим распространенным решением является использование схемы издатель\подписчик и использование распределенной очереди, такой как Kafka, RabbitMQ или даже Redis.

Фактически, Celery может использовать RabbitMQ или Redis в качестве брокера сообщений.

person Gabriel Cappelli    schedule 18.05.2020