![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Перезапуск службы после остановки системой
И. Павел © (2011-12-16 09:37:00)Здравствуйте.
У меня есть служба. В администрирование->службы указал тип запуска: авто и перезапуск службы в случае ошибки. Но при остановке система не перезапускает службу.
Пробовал обернуть код в «main» функции в try/finally и назначать ExitCode := 1. Пробовал выводить исключение нуружу из OnExecute (в этом случае система пишет в журнал, что «service failure», но все равно ее не перезапускает).
Подскажите, пожалуйста, как сделать так, чтобы лыжи ехали?
Заранее спасибо.
PS: на всякий случай приведу код onExecute-метода:
procedure TSEDDeloMonitoringYITService2.ServiceExecute(Sender: TService);
var d: TDateTime;
begin
try
PrepareReg;
CoInitialize(nil);
DMQ.Connect('Provider=SQLOLEDB.1;Password=111;Persist Security Info=True;User ID=tm;Data Source=SQL-SERVER\DELO');
MailThread := TMailThread.Create(false);
while (not Terminated) do
begin
if MailThread.Finished then
break;
d := now;
ShowPosDoc1;
ReportStatus;
ServiceThread.ProcessRequests(false);
if Terminated then break;
ShowPosDoc2;
ReportStatus;
ServiceThread.ProcessRequests(false);
if Terminated then break;
ShowPor;
ReportStatus;
ServiceThread.ProcessRequests(false);
if Terminated then break;
ShowNap;
ReportStatus;
ServiceThread.ProcessRequests(false);
if Terminated then break;
ShowOtch;
ReportStatus;
ServiceThread.ProcessRequests(false);
if Terminated then break;
ShowPosDoc8;
ReportStatus;
ServiceThread.ProcessRequests(false);
if Terminated then break;
SetEmailFlag;
ReportStatus;
ServiceThread.ProcessRequests(false);
if Terminated then break;
SetLastProcessing;
ReportStatus;
ServiceThread.ProcessRequests(false);
if Terminated then break;
d := now + (GetInterval trunc((Now d) * 24 * 60)) / 60 / 24;
while (now < d) and (not Terminated) do
begin
sleep(1000);
ReportStatus;
ServiceThread.ProcessRequests(false);
end;
end;
MailThread.Terminate;
MailThread.WaitFor;
CoUninitialize;
except
on e: Exception do
ExceptHandler(e);
end;
end;
И. Павел (2011-12-17 19:06:00) [1]
> sniknik ©
Большое спасибо. Так и сделаю.
sniknik (2011-12-17 13:03:00) [2]+, пропустил в конце - StartService
sniknik (2011-12-17 13:02:00) [3]> способ перезапуска
WinSvc OpenSCManager OpenService SERVICE_START
перед выходом...
например в проекте
Application.Run;
if isNeedRun then
StartService(selfName); //функция написаная с использованием вышеперечисленного
И. Павел (2011-12-17 12:09:00) [4]
> Сергей М. © (16.12.11 16:10) [25]
> Anatoly Podgoretsky © (16.12.11 16:22) [26]
Теперь понимаю. Должно быть не exception а что-то посерьезнее. И сказать системе, что сервис Delphi завершился крахом не получится... А вручную устраивать крах (например, stack overflow с помощью рекурсии) ради того, чтобы перезагрузить сервис, это не дело... (хотя - как запасной вариант может и сгодится :)
Но может быть можно как-нибудь упростить рестарт сервиса после ошибки? Например, внутри проекта-сервиса? Как-то хитро написать main-функцию. Или все же единственный выход: делать все вручную? Ведь если не перезапускать сервис, нужно будет волноваться о том, что не все ресурсы освободились...
Если восстанавливать сервис после сбоя вручную, то пока что единственное, что мне приходит в голову, это организовать обработчик OnExecute сервиса следующим образом:
procedure TSEDDeloMonitoringYITService2.ServiceExecute(Sender: TService);
begin
while true do
begin
<всем ресурсам сервиса (потокам и т.д.) присваиваю nil>
try
try
<инициализирую ресурсы сервиса (например - создаю и запускаю потоки и т.д.)>
while not Terminated do
begin
<тут происходит основной цикл работы сервиса>
end;
except
on e: Exception do
<тут сообщаю об ошибку: пишу в журнал, отсылаю email и т.д.>
end;
finally
<проверяю, если какой-то ресурс сервиса <> nil, то очищаю его (если поток - то перед очищением шлю команду на завершение и waitfor)>
end;
end;
end;
Подскажите, пожалуйста, есть ли какой-нибудь другой способ перезапуска или просто восстановления сервиса после ошибки (имею ввиду exception, а не системный сбой)?
Anatoly Podgoretsky (2011-12-16 16:22:00) [5]> И. Павел (16.12.2011 15:53:22) [22]
Но ты то хочешь после остановке системой, а этого не будет. Система может
перезагрузить только после краха
Сергей М. (2011-12-16 16:10:00) [6]
> ак лучше организовать процесс обработки исключений?
Как всегда - анализируя объект-исключение.
И. Павел (2011-12-16 16:08:00) [7]> [23] Сергей М. © (16.12.11 15:59)
Просто это проблематично, т.к. для какого-то исключения нужно переподключаться к базе данных а другое просто пропустить и повторить действие в следующей итерации, третье может потребовать пересоздать какие-то объекты, сперва их удалив (что, в свою очередь, тоже может вызвать исключение) и т.д.
Тогда как лучше организовать процесс обработки исключений?
Организовывать в OnExecute цикл, внутри которого будет try/except? Или можно сделать этот цикл на уровне «main» файла программы? Скажем, постоянно вызывая Application.Run?
И еще: может все-таки можно как-нибудь средствами Delphi сказать системе, что сервер останавливается с ошибкой и его нужно перезапустить?
Сергей М. (2011-12-16 15:59:00) [8]
> это позволит выполняться ей в режиме 24/7
Зачем же ты тогда не гасишь исключение, сознательно выпуская его наружу ?
Не выпускай, обрабатывай - и будет он в режиме 24/7.
А если не будет, то это и есть авария - вот тогда SCM его перезапустит. Если он сам к этому моменту не труп)
И. Павел (2011-12-16 15:53:00) [9]> [21] И. Павел © (16.12.11 15:50)
Просто я специально переписал программу в службу, рассчитывая, что это позволит выполняться ей в режиме 24/7. А если что-то пойдет не так, система ее перезапустит.
И. Павел (2011-12-16 15:50:00) [10]> Зачем ее вообще делать ? Глупее затеи не выдумать)
> Сделай высоконадежный сервис-гвардеец и пусть он следит
> за жизнью основного сервиса и перезапускает его в случае
> нештатного останова.
Но за этим гвардейцем тоже нужно будет следить. Даже если он будет надежным, он все равно может дать сбой. А если и он не будет уведомлять систеу о том, что завершается с ошибкой (как и программа, за которой он следит), то он тоже может остановиться без перезапуска.
Подскажите, пожалуйста, можно ли как-нибудь написать надежный сервис, который информирует систему об ошибке или формирует ошибку при любом своем завершении, так чтобы его всегда перезапускали? Или может быть настроить сервис так, чтобы система перезапускала его даже в случае корректного завершения?
Сергей М. (2011-12-16 15:37:00) [11]
> как сделать аварию?
Зачем ее вообще делать ? Глупее затеи не выдумать)
Сделай высоконадежный сервис-гвардеец - и пусть он следит за жизнью основного сервиса и перезапускает его в случае нештатного останова.
И. Павел (2011-12-16 15:32:00) [12]> [18] Сергей М. © (16.12.11 15:20)
Ясно.
А как сделать аварию? Чтобы Windows сам перезапустил службу?
Сергей М. (2011-12-16 15:20:00) [13]
> отработав 1 минуту и завершившись, не запускается снова
> через 1 мин
Да с чего ей запускаться-то заново ?! С т.з. системы она завершилась вполне штатно, а не аварийно ! Какое системе дело до того что приложение завершило выполение в результате обработки им исключения пользовательского уровня ?
В приложении отработал глобальный (неподконтрольныйтебе) SEH вернего уровня, он штатно "погасил" твое исключение и завершил приложение - разве это авария ?
И. Павел (2011-12-16 14:45:00) [14]> [16] знайка (16.12.11 13:11)
Просто я пока только тестирую службу. Но, скорее всего, на перезапуск поставлю так, как вы сказали, т.к. должны запуститься как минимум драйверы MS SQL.
> [15] Сергей М. © (16.12.11 12:58)
raise после Application.Run тоже не помогает...
Я создал новый проект службы, после Application.Run добавил raise. В OnExecute единственной службы проекта написал простой код ожидания 1 минуту и завершения:
var i: integer;
begin
for i := 1 to 60 do
begin
sleep(1000);
ReportStatus;
end;
raise Exception.Create('Error Message');
Но эта служба, отработав 1 минуту и завершившись, не запускается снова через 1 мин, хоть в ее настройках я это указал...
Если у кого-нибудь есть пара свободных минут, попробуйте сделать такой-же проект. Перезапускается ли служба? Пока пишу на Delphi XE. Не думаю, что в Delphi 7 что-то изменится, но сейчас установлю его и попробую сделать то же самое. OC: Windows 7.
Вот архив с проектом простой службы для Delphi XE, о которой я говорил: http://ifolder.ru/27620988
знайка (2011-12-16 13:11:00) [15]
> Именно не перезапускается
Ну как уже говорили, при штатной остановке система ее не перезапустит.
А так у вас какая-то неправильная служба, если она не 24/7 то это и не служба вовсе. :)
Сергей М. (2011-12-16 12:58:00) [16]> Я делал через raise
Этот raise неимеет отношения к необработанным исключениям ОСНОВНОГО треда сервис-приложения, которые могут привести к его аварийному падению и , соотв-но, к перезапуску приложения системой.
И. Павел (2011-12-16 12:39:00) [17]> if MailThread.Finished then
> break;
> if MailThread.Finished then
> raise ....;
> Она же шатно остановилась, а не упала аварийно ..
> С чего бы системе ее перезапускать ?
Я делал через raise. При этом удалял блок except. Все равно не востанавливается.
> [11] знайка (16.12.11 10:58)
Именно не перезапускается, т.е. даже если запустить вручную, нажав кнопку «запуск» в свойствах службы все равно не перезапускается после останова.
Сергей М. (2011-12-16 12:34:00) [18]
> при остановке система не перезапускает службу
Она же шатно остановилась, а не упала аварийно ..
С чего бы системе ее перезапускать ?
Anatoly Podgoretsky (2011-12-16 11:42:00) [19]> RWolf (16.12.2011 10:15:02) [2]
Видимо сеть или что то другое хочет, а этого еще нет
знайка (2011-12-16 10:58:00) [20]А отложенный запуск (Delayed Start) пробовали ставить?
Иногда не все еще стартонуло, и надо ждать. Например у нас так с базой, наш сервис пытается стартовать раньше, при запуске системы, поэтому включили отложенный запуск.