@HiLevel
Нет лучше кода, чем говно у входа

Как запустить массивную задачу на php?

Здравствуйте! Есть php скрипт, который подкачивает через чужое апи около нескольких миллионов (а то и миллиардов) значений. Вопрос в том, как данный скрипт можно реализовать (можно даже через другие ЯП), чтобы он спокойно загружался столько, сколько ему нужно(полагаю, займет не один час), ведь при открытии браузером, через некоторый промежуток времени вылазит 500 ошибка
  • Вопрос задан
  • 568 просмотров
Решения вопроса 2
DevMan
@DevMan Куратор тега PHP
все долгоиграющее должно запускаться в фоне, а не браузером/веб-сервером.
Ответ написан
Комментировать
usdglander
@usdglander Куратор тега PHP
Yipee-ki-yay
Либо
set_time_limit(0);
либо запускайте в обход веб-сервера из консоли.
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
bigton
@bigton
Web-программист
Все таки на PHP писать скрипты, которые должны выполняться часами, не самая лучшая идея.
Каждую большую задачу можно разбить на маленькие.

Допустим, вам надо скачать информацию по всем товарам магазина.
Информация находится по адресу https://api.site.ru/item/N, где N - ID товара от 1 до 1М.

1. Сделаем таблицу задач со следующей структурой:
- task_id
- item_url (например, https://api.site.ru/item/1)
- status (0 - задача не обработана, 1 - задача в работе, 2 - задача завершена)
- process_id (ID PHP процесса который занял задачу для выполнения)

2. Напишем простой скрипт, который будет брать из таблицы задач одну задачу, скачивать информацию по товару, сохранять ее и завершаться. Тут самое сложное, сделать так, чтобы два параллельных запуска этого скрипта не взялись выполнять одну и туже задачу. Для этого можно сделать что-то типа

$process_id = microtime(TRUE).getmypid(); // некоторое уникальное значение

// попытка занять свободную задачу на выполнение
$mysqli->query("UPDATE `task` SET `process_id` = $process_id WHERE `status` = 0 AND `process_id` = 0");

// получаем информацию по задаче
$mysqli->query("SELECT * FROM `task` WHERE `process_id` = $process_id");

// выполняем задачу, что-то скачиваем
...

// ставим в таблице задаче статус "завершена"

3. Теперь надо только организовать постоянный запуск этого скрипта.

Создадим sh скрипт, например, task.sh и поставим в кроне его запуск на каждую минуту.
Сам же скрипт будет каждую секунду вызывать task.php.

#!/bin/bash

for i in $(seq 0 59)
do
    
    if [ `ps aux | grep -c task.php` -le 10 ]; then
	    /usr/bin/wget -q -O /dev/null http://localhost/task.php &
    fi

    sleep 1;	
done


Заключение. Таким образом вы сможете контролировать ход выполнения глобальной задачи, смотреть какие микрозадачи подвисли и отправлять их на перезапуск. Предложенное решение можно сильно улучшить.
Ответ написан
@koeshiro
Читам:
  1. proc_open
  2. stream_set_blocking
  3. stream_select

Это позволит хорошо работать с дочерними процессами и хорошо обрабатывать большое количество задач.
Ответ написан
Комментировать
@iitovka
на крон задачу поставить
Ответ написан
Комментировать
OnYourLips
@OnYourLips
Создаете systemd юнит для запуска в фоне.
Подход нормальный.
Не кроном.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы