Лимит на реальное (не процессорное!) время работы скрипта

  • Автор темы Dmitry Koteroff
  • Дата начала

Dmitry Koteroff

Guest
Лимит на реальное (не процессорное!) время работы скрипта

set_time_limit() в Unix устанавливает лимит на ЧИСТОЕ ПРОЦЕССОРНОЕ время работы скрипта. Можно ли каким-либо способом ограничить РЕАЛЬНОЕ время работы?

Поясню, зачем это нужно. Функция ibase_query() в режиме транзакции IBASE_WAIT (ждущей) в случае конфликта может "подвисать" на неопределенное время (пока ресурс не освободится). Нужно сделать, чтобы это подвисание длилось не больше 10 секунд, а потом выдавалось сообщение, и скрипт завершался.

Я пока не нашел работающего способа. Пробовал:
- set_time_limit()
- declare(ticks=1)
- pcntl_alarm() (увы, этой функции нет в mod_php, только в cgi!)

Может быть, кто-то знает еще метод?
 

tony2001

TeaM PHPClub
насколько я понимаю, пока ibase_query() ждёт, процесс PHP не выполняется, а ждёт нужного ресурса, соотв-но, PHP не может и прерваться.
у клиента Interbase нет какого-то своего таймаута?
 

si

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

P.S. почитал про обработку сигналов в mod_perl там тоже проблемы у них, судя по всему единственно нормальный способ это обрабатывать это в апаче
 

Vasya

Guest
Насчет "а потом выдавалось сообщение" не знаю.
А прибить зависший процесс по сигналу можно.
Сначала надо узнать его PID.
http://ru.php.net/manual/ru/function.getmypid.php
Затем из скрипта поставить внешний таймер, который и прибьёт процесс `kill -9 $PID`. Тут правда возникают проблемы с пермишнами и прочее. Но, так как скрипт не выполняется в ожидание выполнения запроса к ИБ, то ясно, что надо его отрубать чем-то внешним.
Крооче, демон рядышком повесить, которому передавать задания типа "если не проснусь через 10 сек, то прибей" и "я проснулся -- прибивать не надо" :)
 

Dmitry Koteroff

Guest
> видимо есть какие-то причины почему это не
> реализовано для mod_php
Есть, и они просты: Apache сам использует SIGALRM. Я недавно в этом как раз ковырялся (правда, для других вещей), так что на печальном опыте знаю, как там все запутано. :)

Демона, конечно, можно. Только с тем расчетом, что прибивать нужно не любой скрипт, если он висит 10 сек, а только тот, что висит внутри ibase_query(). Ибо могут быть скрипты, работающие долго совершенно легально (например, скрипт приема multipart-формы может целый час работать, и его нельзя трогать). Так что демон должен как-то определять, в каком состоянии скрипт, и предпренимать соответствующие действия.

В принципе, можно, наверное, и без демона: пусть скрипт пишет куда-нибудь и постоянно обновляет свой PID и текущий статус, а в начале работы - сканирует это все и прибивает зажравшихся (posix_kill). Т.е. каждый следующий запрос прибивает часть висящих существующих.

Криво это все, конечно.
 

Vasya

Guest
Я имел в виду примерно такой подход:
PHP:
toDemon("собираюсь обратиться к ИБ... Ну, ты знаешь что делать.", getmypid());
ibase_query('...');
toDemon("всё нормально. отбой.", getmypid());
Можно сделать ещё более извращенно. Демон раз в 5(10) секунд делает `netstat -an --program |grep $IB_PORT| grep httpd| grep ESTABLISHED` Суть в том, чтобы узнать PID'ы активных соединений из апача к ИБ. Затем, долговисящие прибиваются.
Этот способ не требует никаких переделок в ПХП.
 

si

Administrator
В принципе, можно, наверное, и без демона: пусть скрипт пишет куда-нибудь и постоянно обновляет свой PID и текущий статус, а в начале работы - сканирует это все и прибивает зажравшихся (posix_kill). Т.е. каждый следующий запрос прибивает часть висящих существующих.
вариант с демоном както красивее выглядит, естественно демону надо говорить за кем и когда следить, это может сам скрипт и делать, через tcp,sock или любой другой ips
 

AnToXa

prodigy-одаренный ребенок
а если без ipc, а просто fork()? + в environment выставляем дочке время сколько жать ну а пид доча сама найдет.

-~{}~ 14.06.05 23:09:

еще можно попытаться достать дескриптор соединения из ресурса соединения и сделать просто select с таймаутом :)
 

tony2001

TeaM PHPClub
si
>вариант с демоном както красивее выглядит
IMO не очень красиво и очень замороченно.
из пушки по воробьям.

AnToXa
>еще можно попытаться достать дескриптор соединения из ресурса соединения и
>сделать просто select с таймаутом

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

AnToXa

prodigy-одаренный ребенок
tony2001
мне кажется, если б там был какой-то дескриптор, то это было бы сделано в самом API.
по крайней мере, это логично (хотя, искать логику у авторов DB API обычно бесполезно, да).
файловый дескриптор :) который соединения :) закрыть его просто асинхронно и всех дел.
 

Dmitry Koteroff

Guest
> из пушки по воробьям
Вот и я тоже склоняюсь к такому мнению...

> просто fork()
Низя в mod_php!

> netstat -an --program |grep $IB_PORT| grep httpd| grep ESTABLISHED
Увы, так не получится - ибо должно быть запрещено прибивать долгоиграющие процессы, которые держат соединения с IB, но при этом НЕ ВИСЯТ в ожидании в ibase_query(), а делают что-то еще (например, скрипт рассылки).
 

Vasya

Guest
... запрещено прибивать долгоиграющие процессы, которые держат соединения с IB, но при этом НЕ ВИСЯТ в ожидании в ibase_query()...
ОК. Откуда можно получить информацию о том, что скрипт висит, именно ожидая ibase_query()? Imho, только от самого скрипта. Тогда остается обрамлять каждый вызов ibase_query() своеобразным try/catch, осуществлять который будет кто-то внешний.
 

Screjet

Новичок
Dmitry Koteroff
Если есть выделенный сервак, может есть смысл доработать ibase-либу на предмет таймаута?
 

alexhemp

Новичок
Вообще лучше избегать таких "длинных" транзакций в IB/Firebird.

А можно поинтересоваться, почему именно WAIT транзакция?
Обычно они и приводят к Deadlock-у, что собственно и наблюдается...

Если это Web-приложение то почему не использовать NO WAIT?

Или как альтернативу, можно попробовать уменьшить интервал DEADLOCK_TIMEOUT который отвечает за время которое будут "висеть" заблокированные транзакции.
 

Dmitry Koteroff

Guest
> может есть смысл доработать ibase-либу на предмет
> таймаута?
Возможно. Но я не вижу, как это сделать, если возможность использования SIGALRM недоступна.

> А можно поинтересоваться, почему именно
> WAIT транзакция? Обычно они и приводят к
> Deadlock-у, что собственно и наблюдается...
Нет. Вы путаете понятие "дедлок" и "долгое ожидание". Это ПРИНЦИПИАЛЬНО РАЗНЫЕ вещи. Рекомендую почитать статью http://www.isp.idknet.com/development/interbase/devinfo/ibtrans.htm - только ее надо очень внимательно читать, ибо с первого раза трудно разобраться.

Вкратце сухой остаток такой. Дедлок - это когда A ждет B, а B ждет A, и это будет ГАРАНТИРОВАНО происходить до бесконечности, если только A или B не отвалится. Такие ситуации легко распознаются (наличие циклов в каких-то там графах, точно уже не помню). А "долгое ожидание" - это вовсе даже не дедлок, потому что это НЕ взаимное ожидание, а просто ожидание транзакции A транзакцией B (но НЕ наоборот). Соответственно, IB распознает дедлоки, но термин "распознать долгое ожидание" бессмысленен - ибо ничего криминального в "долгом ожидании" нет.

NOWAIT использовать недопустимо! И ОСОБЕННО - в web-области. Посудите сами: запустят 2 человека одновременно один и тот же скрипт, и в случае NOWAIT один из них отвалится с ошибкой. Это некорректное поведение! В таких случаях второй скрипт должен подождать, пока разрешатся все конфликты с первым, и корректно выполниться.

Есть еще вариант: в цикле долбить запрос в NOWAIT-режиме, а если не получилось, то выждать секунду (или случайный интервал) и повторить еще раз - и так в течение 10 секунд. В принципе, такой способ рабочий (схема используется, например, при коллизиях пакетов в Ethernet-сетях), однако он КРИВОЙ - потому что приводит к излишним простоям в случае большого числа одновременных запросов.
 

tony2001

TeaM PHPClub
Dmitry Koteroff
может, стоит переложить нужные для Веб данные в другую базу и сделать "посредника" между ними (который уже будет подвержен проблеме с таймаутом).
вообще, Интербейз там откуда?
наверняка ведь какая-то система внутренняя с ним работает, так?
 

tony2001

TeaM PHPClub
ну, например в PG есть async queries - [m]pg_send_query[/m].
кроме того, можно за счет выкладывания только нужной информации уменьшить её объем и ускорить это всё.
 

si

Administrator
на мой взгляд с базой тут проблем нет, она честно выполняет свою работу, проблема тут в невозможность в mod_php использовать alarm/signal

-~{}~ 15.06.05 10:47:

ну, например в PG есть async queries - pg_send_query
ага, хорошая штука.

но мне кажется ставить вторую баз, делать репликацию в нее посложнее варианта с демоном-убийцей
 
Сверху