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].
Думал насчет семафоров, но как-то не внушают они мне доверия. Боюсь, что стабильность только ухудшится.
Есть скрипт (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].
Думал насчет семафоров, но как-то не внушают они мне доверия. Боюсь, что стабильность только ухудшится.