служба Windows c idHTTPServer, 2 вопроса

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

служба Windows c idHTTPServer, 2 вопроса

Сообщение jsa » 12.01.2024 11:14:01

Здравствуйте.
Имеется на Lazarus написанная служба windows.
Используется многопоточный idHTTPServer работает в нескольких местах.
Везде стабильно. Но в одном месте приходят тяжелые запросы сразу пачками по 6-8 штук каждые 10 сек.
Через 2-3 часа работы служба виснет.

пока сделали bat-ник который каждые 10 сек "пингует" ее curl-ом с запросом -X HEAD и если нет ответа определяет PID процесса, прибивает службу и перезапускает.
Но это костыль, и нужно разобраться.

Навтыкал во многих местах try except и сохраняю исключение через логгер класса TCustomDaemon
Код: Выделить всё
RestService.LogMessage(FormatDateTime('YYYY-MM-DD_hh:nn:ss.zzz',NOW)+ ' Exception {тут вставляю имя функции} --- '+E.ToString );


Отловил странную ошибку.
EAccessViolation: Access violation
в процедуре создания объектов TMSSQLConnection, TSQLTransaction, TSQLQuery они создаются в каждом потоке и удаляются перед закрытием.

Обновил библиотеку dblib.dll с версии 1.0 на 1.3
А создание компонент оформил циклом из нескольких попыток, с паузой между попытками.
Повторно эта ошибка пока не появлялась.
Но хочется понять смысл, почему ограничивается доступ. Что вероятнее? проблема с многопоточностью библиотеки или MS SQL ограничивает частоту и кол-во подключений? (не встречал ни разу такую настройку).

Так же происходят зависания, которые не попадают в виндовый журнал. Сижу расставляю дальше try excep . А может есть какая то настройка у TDaemon? чтобы все критические события в работе автоматом записывались в журнал, и не было нужды расставлять везде try except?
jsa
постоялец
 
Сообщения: 282
Зарегистрирован: 28.11.2017 13:46:04

Re: служба Windows c idHTTPServer, 2 вопроса

Сообщение WAYFARER » 12.01.2024 13:11:51

jsa писал(а):Через 2-3 часа работы служба виснет.

Известно по какой причине виснет?
Аватара пользователя
WAYFARER
энтузиаст
 
Сообщения: 537
Зарегистрирован: 09.10.2009 00:00:04
Откуда: г. Курган

Re: служба Windows c idHTTPServer, 2 вопроса

Сообщение jsa » 12.01.2024 13:36:09

WAYFARER писал(а):
jsa писал(а):Через 2-3 часа работы служба виснет.

Известно по какой причине виснет?

Так я причину и пытаюсь определить втыкая обработки исключений по всему тексту.
jsa
постоялец
 
Сообщения: 282
Зарегистрирован: 28.11.2017 13:46:04

Re: служба Windows c idHTTPServer, 2 вопроса

Сообщение WAYFARER » 12.01.2024 14:35:57

jsa писал(а):Так я причину и пытаюсь определить втыкая обработки исключений по всему тексту.

Не верно понял, извиняюсь.
Вообще с многопоточностью это больная тема, библиотека и SQL Server скорее всего ни при чем, Чаще это попытки обратиться к уже несуществующим объектам или попытке одновременного обращения разных потоков к одной и той же области памяти.
jsa писал(а):Так же происходят зависания, которые не попадают в виндовый журнал.

В журнал будут попадать ошибки только пока служба отвечает либо упала совсем. А у вас она не упала, она просто висит. И вообще есть вероятность что зависания не связаны с возникающими ошибками, может тупо данными подавиться, ресурсов не хватить. Я бы рекомендовал добавить логирование в программу и записывать в лог все, что программа делает в реальном времени, тогда можно будет примерно увидеть что происходило перед зависанием, в том числе и исключения туда писать.

jsa писал(а):пока сделали bat-ник который каждые 10 сек "пингует" ее curl-ом с запросом -X HEAD и если нет ответа определяет PID процесса, прибивает службу и перезапускает.
Но это костыль, и нужно разобраться.

У меня почти такие же костыли. У меня используется демон-папа, который отслеживает состояние в реальном времени и перезапускает по необходимости. Но в случает когда служба работает с данными это очень плохое решение...
Аватара пользователя
WAYFARER
энтузиаст
 
Сообщения: 537
Зарегистрирован: 09.10.2009 00:00:04
Откуда: г. Курган

Re: служба Windows c idHTTPServer, 2 вопроса

Сообщение stikriz11 » 12.01.2024 18:38:53

jsa писал(а):Так я причину и пытаюсь определить втыкая обработки исключений по всему тексту.
jsa
постоялец
 
Сообщения: 254
Зарегистрирован: 28.11.2017 12:46:04

А Вы сделайте запуск как приложения. Проще будет отлаживать.

if (ParamCount > 0) and (UpCase(ParamStr(1)) = '-A') then
begin
Forms.Application.Title:='Запустились аплиухой';
Forms.RequireDerivedFormResource:=true;
Forms.Application.Scaled:=True;
Forms.Application.Initialize;
Forms.Application.CreateForm(TfПростоФорма, которая при открытии создаст и запустит демон, fформааплиухи);
Forms.Application.Run;
end
else
begin
DaemonApp.Application.Initialize;
Application.Run;
end;
Это в модуле проекта
stikriz11
постоялец
 
Сообщения: 126
Зарегистрирован: 04.09.2023 15:54:19

Re: служба Windows c idHTTPServer, 2 вопроса

Сообщение jsa » 15.01.2024 12:24:48

stikriz11 писал(а):А Вы сделайте запуск как приложения. Проще будет отлаживать.

Идею не понял.
А именно как это работает и что это облегчает.
jsa
постоялец
 
Сообщения: 282
Зарегистрирован: 28.11.2017 13:46:04

Re: служба Windows c idHTTPServer, 2 вопроса

Сообщение stikriz11 » 15.01.2024 12:45:17

jsa писал(а):Идею не понял.

Любой демон можно запустить как обычное приложение. TDaemon - это потомок от TDataModule.
Можно параметром передать как именно мы запускаем. Я использую параметры запуска - Параметр командной строки, допустим, -А
При запуске в модуле проекта мы проверяем, есть ли такой параметр и если да, то запускаем как приложение.
Есть два модуля: DaemonApp - там демон и все, чтобы запускать демон, и Forms - там все, чтобы запускать приложение с формами.
Если параметр есть, то мы не обращаемся к модулю DaemonApp , а обращаемся к Forms. В нем мы инициализируем приложение и создаем форму, которая будет просто видна. При создании этой формы, мы создаем демон - это просто потомок от датамодуля. И вызываем ему Start. Все будет работать так же точно, как и демон. Но, Вы сможете обычным способом отлаживать приложение и ловить ошибки. Идея в том, чтобы отлаживать как приложение, а потом уже запускать как демон, когда все отдажено
public
function Start: Boolean; override;
function Stop: Boolean; override;
stikriz11
постоялец
 
Сообщения: 126
Зарегистрирован: 04.09.2023 15:54:19

Re: служба Windows c idHTTPServer, 2 вопроса

Сообщение jsa » 15.01.2024 12:51:36

WAYFARER писал(а):Известно по какой причине виснет?

Отловил два исключения связанные с MS SQL сервером. И написал их обработку.

Еще одно исключение возникает при сборе параметров входящего url запроса в динамическую таблицу
Код: Выделить всё
глобально

type    Tprm1 = record name, value: string; end;//тип для создания массива параметров входящего запроса     

в многопоточной процедуре

var prms:array of Tprm1;

begin

try
// кол-во параметров берется тут
prms_cnt:=ARequestInfo.Params.Count;
rJdataStr := ARequestInfo.UnparsedParams;

// массив динамический, устанавливается размер
SetLength(prms,prms_cnt);
except
... //исключение ( EAccessViolation: Access violation ) возникает именно в этом блоке 
end;

// далее массив наполняется параметрами

end;

Тут ощущение, что проблема с переменной динамической таблицы в потоке.


Возможно есть еще одно исключение которое еще не обернул в try...except

Добавлено спустя 4 минуты 18 секунд:
stikriz11 писал(а):Но, Вы сможете обычным способом отлаживать приложение и ловить ошибки. Идея в том, чтобы отлаживать как приложение, а потом уже запускать как демон, когда все отдажено

Метод не годится.
Проблемы проявляются на рабочем сервере под реальными нагрузками и только в одном месте.
Заниматься подобной отладкой на сервере нет возможности.
сейчас батник "пингует" службу и тут же перезапускает ее при зависании.
А у меня есть возможность только заменять exe-шник и анализировать логи программы и виндовые логи с новыми точками записи.
jsa
постоялец
 
Сообщения: 282
Зарегистрирован: 28.11.2017 13:46:04

Re: служба Windows c idHTTPServer, 2 вопроса

Сообщение xchgeaxeax » 15.01.2024 15:08:24

Попробуйте строку параметров копировать, а не присваивать:
Код: Выделить всё
if Assigned(PChar(ARequestInfo.UnparsedParams))
  then rJdataStr := copy(ARequestInfo.UnparsedParams, 1, Length(ARequestInfo.UnparsedParams))
  else rJdataStr := default(srting);
Возможно строка пропадает до её разбора или вовсе отсутствует. Отсюда и AccessViolation. Еще, возможно, из-за мусора в динамическом массиве prms. Установите его в nil перед
Код: Выделить всё
prms := nil;
SetLength(prms, prms_cnt);
xchgeaxeax
постоялец
 
Сообщения: 125
Зарегистрирован: 11.05.2023 03:51:40

Re: служба Windows c idHTTPServer, 2 вопроса

Сообщение WAYFARER » 16.01.2024 10:07:48

xchgeaxeax писал(а):Еще, возможно, из-за мусора в динамическом массиве prms. Установите его в nil перед

Так а откуда там мусор возьмется, если AV происходит до начала работы с массивом, а переменная prms локальная?
И тут вообще непонятно, AV до выделения памяти для prms или после? Тут вообще по куску кода без контекста мало что понятно. jsa, может где то процедура где то лезет в основной поток без синхронизации?
Аватара пользователя
WAYFARER
энтузиаст
 
Сообщения: 537
Зарегистрирован: 09.10.2009 00:00:04
Откуда: г. Курган

Re: служба Windows c idHTTPServer, 2 вопроса

Сообщение xchgeaxeax » 16.01.2024 11:56:20

WAYFARER писал(а):Так а откуда там мусор возьмется, если AV происходит до начала работы с массивом, а переменная prms локальная?
И тут вообще непонятно, AV до выделения памяти для prms или после? Тут вообще по куску кода без контекста мало что понятно. jsa, может где то процедура где то лезет в основной поток без синхронизации?

Согласен. Вопросов тут много. Но, как показывает опыт, в таких простых местах ошибки AV исправляются присвоением начальных значений для переменных до вызовов выделяющих память. Так же неизвестно как он формирует и использует объект ARequestInfo. Поэтому стоит не создавать ссылку на его строку, а копировать данные в новый буфер для текущего потока. А в целом должен помочь вывод в лог значений переменных в блоке вызвавшем AV (для указателей - значений указателей, а не данных по ним).
xchgeaxeax
постоялец
 
Сообщения: 125
Зарегистрирован: 11.05.2023 03:51:40

Re: служба Windows c idHTTPServer, 2 вопроса

Сообщение stikriz11 » 16.01.2024 14:03:25

Хорошо, если ошибка в работе с памятью там, где она вылазиет, а не в произвольно любом другом месте. Heaptrcon не пробовали? Ах, да. У Вас же нет возможности отладки на сервере...
stikriz11
постоялец
 
Сообщения: 126
Зарегистрирован: 04.09.2023 15:54:19

Re: служба Windows c idHTTPServer, 2 вопроса

Сообщение jsa » 19.01.2024 07:18:12

xchgeaxeax писал(а):опробуйте строку параметров копировать, а не присваивать:

Постепенно сужая проблемные места и наблюдая логи определил

1. Проблема не в копировании
Код: Выделить всё
rJdataStr := ARequestInfo.UnparsedParams;

в самое начало процедуры вынес перенос в свои переменные значения всего используемого из ARequestInfo
Ошибка точно в функции
Код: Выделить всё
rJdataStr := TIdURI.URLDecode( rJdataStr );

я ее тоже обернул в try except, регулярно выдает исключение Invalid pointer operation

2. Ошибку при создании TMSSQLConnection, TSQLTransaction, TSQLQuery исключил, проблема не в создании, а именно в подключении MSSQLConnect.Open;
попытки подключения поместил в цикл с sleep(500) и прерываем после 5 неудачных.
Пока не проявлялось.

3. Остаются загадочными несколько зависаний-перезапусков службы т.к. от них нет никаких записей в виндовый журнал.
Попробовал сделать обработку в event
IdHTTPServer1Exception
После нескольких часов выяснилось, что эта обработка ничего не сохраняет в лог.
Или я не понял как она должна работать, или просто не дождался. Но пока убрал, потому что кол-во перезапусков службы подозрительно участилось.
jsa
постоялец
 
Сообщения: 282
Зарегистрирован: 28.11.2017 13:46:04

Re: служба Windows c idHTTPServer, 2 вопроса

Сообщение xchgeaxeax » 19.01.2024 07:23:44

jsa писал(а):я ее тоже обернул в try except, регулярно выдает исключение Invalid pointer operation

Попробуйте выводить в лог значения rJdataStr, или ARequestInfo.UnparsedParams. Скорее всего там пусто.
xchgeaxeax
постоялец
 
Сообщения: 125
Зарегистрирован: 11.05.2023 03:51:40

Re: служба Windows c idHTTPServer, 2 вопроса

Сообщение jsa » 19.01.2024 11:52:13

xchgeaxeax писал(а):Попробуйте выводить в лог значения rJdataStr, или ARequestInfo.UnparsedParams. Скорее всего там пусто.

Вывод в лог rJdataStr прямо перед декодировкой поставил.
но
У меня две противоречивые на начальном этапе цели 1. Снизить кол-во перезапусков 2. разобраться с причинами.
т.к. 90% случаев это параметры без кириллицы и символов которые нужно кодировать, пришлось сделать проверку на наличие '%' и если его в строке нет то просто не использовать TIdURI.URLDecode
Поэтому колво зафиксированных ошибок резко упадет.
jsa
постоялец
 
Сообщения: 282
Зарегистрирован: 28.11.2017 13:46:04

След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Google [Bot] и гости: 17

Рейтинг@Mail.ru