Форум программистов, компьютерный форум, киберфорум
Наши страницы
PHP
Войти
Регистрация
Восстановить пароль
 
jasper-blondin
26 / 26 / 10
Регистрация: 19.06.2014
Сообщений: 153
#1

Многошаговый скрипт (самовызов) - PHP

21.12.2016, 18:27. Просмотров 470. Ответов 17
Метки нет (Все метки)

Здравствуйте!

Написал скрипт для сайта, который выполняет некоторые длительные манипуляции с БД и файлами (генерация прайс-листов). Планирую повесить его на CRON (раз в сутки).
Проблема в том, что работа скрипта значительно превышает допустимое время (на хостинге). Может работать до нескольких минут.

Подскажите, как решают такие задачи?

Пока что пришло в голову разбить работу скрипта на шаги. Например, на первом шаге запустить процесс и выполнить одну манипуляцию. После этого запустить новую копию скрипта, но уже с параметром шага. И завершить текущий скрипт, пока не вышло время.
Но я не знаю, как это делается. Например, не понятно, как запустить новую копию скрипта, да еще и с параметрами.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
21.12.2016, 18:27
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Многошаговый скрипт (самовызов) (PHP):

Можно ли делать include php ,при котором если в загружаемом файле есть ошибки,то чтобы необваливался весь скрипт в который загружается другой скрипт?
Можно ли делать include php ,при котором если в загружаемом файле есть...

Скрипт генерирует второй скрипт, трабл с кавычками
Доброго времени суток ! Скрипт должен генерировать еще один скрипт и записать...

Возврат в скрипт, вызвавший данный скрипт
подскажите, допустим есть 1.php <html> <body> <?if (!isset($_REQUEST)) {?>...

PHP скрипт -> Json -> выбор пользователя -> AJAX -> первоначальный PHP скрипт
Доброго времени суток! Я новичек вэб программировании, так что прошу строго...

Многошаговый диалог с пользователем
Здравствуйте, уважаемые коллеги! С недавних пор самостоятельно изучаю Django...

Самовызов
как можно узнать ID процесса самого себя )) т е запущена прога и в этот...

17
Jodah
Эксперт PHP
2704 / 2376 / 1013
Регистрация: 01.08.2012
Сообщений: 8,405
21.12.2016, 18:41 #2
Создаёте в БД таблицу:

cron

id name value
1 generate_prices_last_step 1

Когда крон запускает скрипт, получаем последний выполненный шаг (который лежит в value) и запускаем следующий. И не забываем в конце увеличить последний шаг на 1 (или сбросить, если все шаги выполнены и в след раз нужно начать заново).
0
jasper-blondin
26 / 26 / 10
Регистрация: 19.06.2014
Сообщений: 153
21.12.2016, 19:56  [ТС] #3
Можете немного подробнее описать механизм?

Пока что я понял ответ так: CRON запускает скрипт, скрипт проверяет значение в базе, выполняется шаг, изменяется значение в базе, скрипт завершает работу. И все. Остальные шаги не выполняются.
0
Jodah
Эксперт PHP
2704 / 2376 / 1013
Регистрация: 01.08.2012
Сообщений: 8,405
21.12.2016, 21:12 #4
jasper-blondin, с помощью Cron настраиваете запуск скрипта 4 раза в сутки, скажем в 00:00, 00:10, 00:20, 00:30. А в скрипте что-то вроде:

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$step = 1; // Типа взяли последний выполненный шаг из БД
 
$step++; // Получаем шаг, который нужно выполнить сейчас
 
if($step > 4) // Если предыдущий этап был последним, начинаем заново
   $step = 1;
 
if($step == 1)
    include('action1.php');
elseif($step == 2)
    include('action2.php')
elseif($step == 3)
    include('action3.php');
else
    include('action4.php');
 
// Указываем в БД, что текущий шаг успешно пройден
mysql_query('UPDATE `cron` SET `value` = ' . $step . ' WHERE `name` = "generate_prices_last_step"');
0
jasper-blondin
26 / 26 / 10
Регистрация: 19.06.2014
Сообщений: 153
21.12.2016, 21:21  [ТС] #5
Jodah, интересное решение. Однако, я не вижу возможности его использования в случае, когда количество шагов неизвестно или меняется с течением времени (если человек каждый день будет подсчитывать количество шагов и вносить изменения в расписание CRON, сам скрипт потеряет смысл).
0
Jodah
Эксперт PHP
2704 / 2376 / 1013
Регистрация: 01.08.2012
Сообщений: 8,405
21.12.2016, 21:48 #6
Цитата Сообщение от jasper-blondin Посмотреть сообщение
количество шагов неизвестно
А откуда скрипт должен узнавать количество шагов?
0
jasper-blondin
26 / 26 / 10
Регистрация: 19.06.2014
Сообщений: 153
21.12.2016, 22:02  [ТС] #7
Jodah, Приведу пример. Допустим, есть каталог товаров, который содержит множество подразделов. Каждый день в определенное время (полночь) CRON должен запускать скрипт, который генерирует для каждого подраздела прайс-лист. Скрипт составляет список подразделов каталога и пошагово создает прайс-листы. В любой момент в каталоге может появиться новый подраздел или удалиться существующий. Поэтому заранее неизвестно, сколько раз нужно запускать скрипт.
0
Jodah
Эксперт PHP
2704 / 2376 / 1013
Регистрация: 01.08.2012
Сообщений: 8,405
22.12.2016, 09:50 #8
jasper-blondin, ок. Cron запускает скрипт каждые 5 минут в течение часа. Получаем 12 запусков. При первом запуске можно получить кол-во разделов и рассчитать, сколько подразделов должно быть сгенерировано за каждый из 12 запусков.

Проще кодом объяснить.

PHP
1
2
3
4
5
6
7
8
9
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
// Если полночь
if(date('H:i') == '00:00')
{
    // Узнаём, сколько разделов есть на сайте
    $result = mysql_query('SELECT COUNT(*) AS "count" FROM `cats`');
    $result = mysql_fetch_assoc($result);
    $count = $result['count'];
    
    $iterations_count = ceil($count / 12); // Узнали, сколько разделов генерировать при каждом запуске скрипта
    
    // Пишем кол-во разделов в БД
    mysql_query('UPDATE `cron` SET `value` = ' . $iterations_count . ' WHERE `name` = "generate_prices_count"');
    
    // Обнуляем счётчик
    mysql_query('UPDATE `cron` SET `value` = "0" WHERE `name` = "generate_prices_last_cat"');
}
 
// Узнаём, сколько разделов нужно сейчас сгенерировать
$result = mysql_query('SELECT `value` FROM `cron` WHERE `name` = "generate_prices_count"');
$result = mysql_fetch_assoc($result);
$count = $result['value'];
 
// Узнаём, какой раздел был обработан последним
$result = mysql_query('SELECT `value` FROM `cron` WHERE `name` = "generate_prices_last_cat"');
$result = mysql_fetch_assoc($result);
$last_cat_id = $result['value'];
 
// Получаем из БД подразделы для генерации прайсов
$result = mysql_query('SELECT * FROM `cats` WHERE `id` > ' . $last_cat_id . ' ORDER BY `id` LIMIT ' . $count);
 
// Если не осталось необработанных подразделов
if(!mysql_num_rows($result))
    die();
    
while($row = mysql_fetch_assoc($result))
{
    // Генерируем прайс-листы
}
 
// Поскольку в $row лежит последняя обработанная строка и в ней наибольший id из всех, можно сразу подставить его в sql-запрос
mysql_query('UPDATE `cron` SET `value` = ' . $row['id'] . ' WHERE `name` = "generate_prices_last_cat"');
Добавлено через 2 минуты
Если скрипт начнёт падать из-за долгого выполнения, можно будет увеличить количество запусков (с 0 до 2 часов ночи - будет уже 24 запуска).
0
tarasalk
1086 / 640 / 259
Регистрация: 13.06.2013
Сообщений: 2,254
22.12.2016, 10:01 #9
Цитата Сообщение от jasper-blondin Посмотреть сообщение
Поэтому заранее неизвестно, сколько раз нужно запускать скрипт.
Суть от этого не меняется. Просто условие завершения работы надо будет вычислять динамически.

Допустим вам надо обработать N строчек в бд. Просто берете по Y строчек за раз и обрабатываете.
N - не важно сколько. Y - столько, сколько успеете обработать.
0
jasper-blondin
26 / 26 / 10
Регистрация: 19.06.2014
Сообщений: 153
22.12.2016, 20:45  [ТС] #10
Jodah, идея понятна. И вполне имеет право на жизнь.
Правда, придется вычислять дополнительные условия. Например, раздел каталога -- ненормированная величина. В одном разделе может быть 700 товаров, а в другом -- 1200. Получится, что на одних N разделах скрипт отработает, а на других N разделах -- timeout. Или, например, опытным путем подсчитал, сколько шагов делать. Все ок работает. И тут менеджеры добавляют в один из разделов новую партию из 200 товаров. И скрипт на каком-то шаге уходит в timeout. Вся процедура генерации накрылась.

Спасибо за вариант решения задачи!

Хотелось бы услышать вариант, в котором CRON, как планировщик, в определенное время отдает управление в скрипт генерации и забывает о нем. А сам скрипт уже работает, разбивая задачу на шаги, дабы избежать timeout.
0
Jodah
Эксперт PHP
2704 / 2376 / 1013
Регистрация: 01.08.2012
Сообщений: 8,405
22.12.2016, 21:09 #11
Цитата Сообщение от jasper-blondin Посмотреть сообщение
Хотелось бы услышать вариант, в котором CRON, как планировщик, в определенное время отдает управление в скрипт генерации и забывает о нем. А сам скрипт уже работает, разбивая задачу на шаги, дабы избежать timeout.
Насколько я знаю, такого варианта нет. Нельзя сбросить таймер из-за разделения на шаги.

Цитата Сообщение от jasper-blondin Посмотреть сообщение
В одном разделе может быть 700 товаров, а в другом -- 1200.
Тогда пусть Cron запускает скрипт каждые X минут и генерирует прайс для 1 подраздела. Работает пусть в нерабочее время, с 8 вечера до 8 утра.
0
cia
64 / 41 / 17
Регистрация: 19.12.2014
Сообщений: 196
23.12.2016, 20:45 #12
Может так (это псевдокод, чтобы понять смысл)?

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
define('PRODUCT_BY_STEP',1000);
$lastLimit=file_exists('last-limit.txt') ? file_get_contents('last-limit.txt') : 0;
$lastCategoryId=file_exists('last-category-id.txt') ? file_get_contents('last-category_id.txt') : null;
$db->query('SELECT p.* FROM product p INNER JOIN productCategory c ON c.id=p.categoryId ORDER BY p.categoryId LIMIT '.$listLimit.','.PRODUCT_BY_STEP);
$noEnd=false;
while($item=$db->fetchAssoc()) {
  $noEnd=true;
  if($item['categoryId']!=$lastCategoryId) {
    closePriceCategory($lastCategoryId);
    openPriceCategory($item['categoryId']);
    $lastCategoryId=$item['categoryId'];
  }
  addProductToPrice($item);
}
if($noEnd) {
  $f=fopen('last_limit.txt','w');
  fwrite($f,$lastLimit+PRODUCT_BY_STEP);
  fclose($f);
  $f=fopen('last-category-id.txt','w');
  fwirte($f,$lastCategoryId);
  fclose($f);
  echo 'NO END, NEXT STEP REQUIRED';
} else {
  closePriceCategory($lastCategoryId);
  echo 'END!';
}
Добавлено через 1 минуту
Скрипт такой, разумеется на кроне "висит" на каждые 5 пять минут.
0
jasper-blondin
26 / 26 / 10
Регистрация: 19.06.2014
Сообщений: 153
12.01.2017, 15:48  [ТС] #13
Решил задачу так.
При каждом запуске скрипта проверяется некий $_GET параметр. Если он есть, генерация запускается на основе этого $_GET параметра. После чего идет редирект на этот же скрипт, но с другим значением $_GET параметра.
Если $_GET параметр не указан, генерация начинается с "начала" (с первого шага).
CRON запускает скрипт один раз в нужное время, без параметров.
0
cia
64 / 41 / 17
Регистрация: 19.12.2014
Сообщений: 196
17.01.2017, 00:05 #14
А как это: скрипт на кроне и работает редирект?
0
Jodah
Эксперт PHP
2704 / 2376 / 1013
Регистрация: 01.08.2012
Сообщений: 8,405
17.01.2017, 00:16 #15
cia, возможно под редиректом имеется ввиду повторный запрос, например через curl или file_get_contents.
0
cia
64 / 41 / 17
Регистрация: 19.12.2014
Сообщений: 196
17.01.2017, 15:49 #16
Jodah, может. Зачем только такие извращения? Почему бы в файл не сохранять информацию о состоянии импорта...
0
jasper-blondin
26 / 26 / 10
Регистрация: 19.06.2014
Сообщений: 153
05.01.2018, 19:11  [ТС] #17
Забросил тему на год ))

Насколько сейчас помню, повторный запуск скрипта осуществлялся через Header Location.
А вот как решил проблему с первым запуском -- не припомню.
0
little endian
-25 / 5 / 5
Регистрация: 21.12.2017
Сообщений: 59
06.01.2018, 16:56 #18
создаёте файл при запуске, удаляете по окончании
0
06.01.2018, 16:56
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.01.2018, 16:56
Привет! Вот еще темы с решениями:

Необходимо вставить в скрипт увеличения картинки, скрипт просмотра панорамы 360
Здравствуйте. У меня такой специфический вопрос, на моем сайте имеется скрипт...

Объединить скрипт удаления переводов строки и скрипт вставки перевода по специальному символу
Здравствуйте, решаю задачу обработки текстового файла, необходимо сперва...

Скрипт.Нужно из файла csv в AD. и автоматом этот скрипт добавляет 50 пользователей из execl
Import-Module ActiveDirectory $Users = Import-CSV -Delimiter ";" -Path...

Чтобы скрипт на баше запустил через gcc скрипт на c++
Есть скрипт на баше, во время его выполнения нужно чтобы он запустил еще один...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru