Использование get_lock() для отлова прервавшегося скрипта?

Clubber

Новичок
Использование get_lock() для отлова прервавшегося скрипта?

Есть скрипт (script_processing), который выполняет некий длительный процесс. В начале и в конце этого скрипта проставляются таймштампы в базе данных. Они хранятся в разных столбцах: `LOG_START` datetime default NULL, `LOG_END` datetime default NULL. При старте вставляется запись, у которой LOG_START = now(), LOG_END = null. По завершению эта запись апдейтится, и проставляется LOG_END = now().

Эти таймштампы используются другим скриптом (script_status), который докладывает в "почти real-time" режиме юзеру о ходе процесса. Предполагается, что юзерам нужно отдавать данные с ошибкой не больше пяти секунд.

Теперь предположим, скрипт оборвался где-то в середине (например, из-за parse error), и не удалось поставить штамп завершения. Соответственно, юзер умрет от старости, пока дождется завершения :) Казалось бы, можно сделать некий таймаут, по истечению которого можно насильно закрывать лог, но тут тоже есть загвоздка, что скрипт может работать от пары секунд, до десятков минут. Так что введение таймаута никак не вяжется с требованием пятисекундной точности.

Возможное решение [1]:

Script_processing будет после вставки в таблицу открывающего штампа, заводить mysql-евский лок с помощью [sql]select get_lock(CONCAT("stamp_lock_", LAST_INSERT_ID()));[/sql]. И делать release_lock() после закрытия. Соотвественно, script_status может делать выборку а-ля [sql]SELECT FROM `LOG` where LOG_END is null and not IS_FREE_LOCK(CONCAT("stamp_lock_", `LOG_ID`));[/sql], чтобы выбрать все незавершенные логи, чьи скрипты уже отработали, проставить завершающие штампы, послать репорты девелоперам, и отдать _реальный_ статус юзеру.

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

Так что вопрошаю к вам, видите ли вы разумный выход из данной ситуации?

-~{}~ 02.08.06 15:13:

Возможное решение [2]:

Вместо mysql-евских локов использовать файловые.

Все ясно как день. В script_processing, после праставления штампа начала, также создается файл, который тут же лочится. Затем script_status получает незавершенные логи из базы, и в цикле смотрит, залочены ли файлы. Остальное так же.

Вопрос: всегда ли разлочиваются файлы, когда скрипты

Плюсы:
+ решается проблема многочисленных локов.

Минусы:
- Нужно обеспечивать хранилище временным файлам, задавать права.
- Нужен GC для файлов.
- работа с файловой системой вероятно получится медленнее, чем с mysql сервером. Хотя это спички.
- (эстетический) Это как-то не правильно - делать локи, относящиеся к базе данных - используя файлы :|

-~{}~ 02.08.06 15:25:

Вообщем, решение [2] довольно печальное. Хочется, чтобы Решение было стабильным (как [1]), красивым (опять же, как [1]), и обладало плюсом [2].

Думал насчет семафоров, но как-то не внушают они мне доверия. Боюсь, что стабильность только ухудшится.
 

vg2k

Новичок
а мож завести еще одну колонку, в которую скрипт будет каждые X минут докладывать (ставить туда time() допустим) что он жив. Собственно это время X будет риентировочным периодом, и если метка в третей колонке поставлена более X мин назад и скрипт не доложил об окончании => он сдох =)
 

Clubber

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

-~{}~ 03.08.06 09:42:

Возможное решение [3]:

Каждый скрипт script_processing записывает свой PID в отдельную колонку в той же таблице. А script_status проверяет, запущены ли до сих пор эти PIDы. В теории все просто :)

Минусы/проблемы:
- проверка, работает ли до сих пор процесс с нужным PIDом - нетривиальная.
- PIDы могут со временем повторяться. Но вероятность того, что (первый скрипт оборвался) && (штамп не закрыт) && (к моменту запуска следующего script_status скрипта PID уже занялся опять) - значительно меньше.
- Не может ли быть так настроены апаче и пхп, PID не будет освобождаться после завершения скрипта, а удерживаться апачем?
 

vovik

Новичок
Не утверждаю что это хороший вариант, но мне кажется, что работать будет.

Скрипт, который долго работает, открывает транзакцию. И пишет в табличку данные, что он работает. Транзакцию не закрывает ;)

Скрипт, который проверяет, делает периодическое грязное чтение (на уровне READ UNCOMMITTED). Если данные есть - работа идет.

Если первый скрипт отваливается - транзакция автоматически откатывается и данные исчезают.


Ну это в общем, доработать под задачу конечно нужно, главное - идея :)
 

Clubber

Новичок
vovik
Хороший вариант :)

InnoDB для этих целей подойдет? Ничего же страшного не будет, из-за того, что остальные таблицы - MyISAM ?
 

vovik

Новичок
Да, подразумевается конечно InnoDB. И ничего страшного от смешения разных типов в одной БД не будет.

Но надо тестировать, мне это сейчас в голову только пришло, я мог что-нибудь не предусмотреть :)
 
Сверху