gifts2017

Автоматический перезапуск службы агента сервера 1С Предприятия 8.

Опубликовал Алексей С. (AlexS2) в раздел Администрирование - Системное

Решение проблемы с утечками памяти рабочих процессов сервера 1С Предприятия средствами операционной системы.

Известно, что при функционировании рабочих процессов сервера 1С Предприятия 8.1 rphost.exe существует следующая проблема: из-за особенностей платформы, с подключением каждого нового клиента к рабочему процессу, увеличивается размер занимаемой рабочим процессом оперативной памяти. При этом, при отключении клиента, занимаемый при подключении объем не освобождается. Так же объем памяти, занимаемый рабочим процессом может увеличиваться при выполнении программного кода. Данное поведение называется “Утечками памяти” или “Memory Leaks”. В итоге, когда объем занимаемой памяти процессом rphost.exe вырастает больше опеределенного предела (в моем случае это было >1Gb), рабочий процесс безусловно перезапускается. Понятно, что клиенты, подключенные к этому процессу, получают сообщение, что соединение с сервером разорвано, прекращают работу и вынуждены переподключаться. В зависимости от количества пользователей и количества запущенных рабочих процессов, данная проблема возникает с той или иной частотой. В моем случае - пользователей порядка 60 и один рабочий процесс, подобная ситуация возникала до 5 раз в неделю. Т.е. ни о какой стабильной работе системы 1С Предприятие в этом случае речь не идет.

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

Второй и вполне логичный шаг - автоматический перезапуск процессов на сервере, о чем, собственно, и хочется написать.

Поскольку служба агента сервера 1С Предприятия представляет собой стандартную службу, в арсенале Windows есть стандартный способ остановки и запуска служб из командной строки командами net stop и net start. Достаточно эти команды лишь включить в bat-файл и настроить шедулер на запуск bat-файла по расписанию, я настроил перезапуск один раз в сутки, в ночное время. Следует иметь ввиду, что если перезапускать рабочие процессы в рабочее время, все подключенные к серверу 1С Предприятия клиенты будут отключены!
Кроме того, чтобы немного разнести по времени команды остановки и запуска службы, будем использовать известную утилиту sleep.exe, которую легко найти в Сети.

Примерный текст bat-файла restart1c.bat:

rem @echo off
rem \\----- начало скрипт остановки и запуска агента сервера 1С Предприятия----\\
set logfile="stopstartlog.txt"
set timeout=20
echo %date% %time% >>%logfile%
net stop "1C:Enterprise 8.1 Server Agent" >>%logfile%
c:\scripts\sleep %timeout%
echo %date% %time% >>%logfile%
net start "1C:Enterprise 8.1 Server Agent" >>%logfile%
c:\scripts\sleep %timeout%
rem \\----- конец скрипт остановки и запуска агента сервера 1С Предприятия----\\

Объяснение используемых переменных и команд:
* logfile - файл stopstartlog.txt, куда будут записываться результаты выполнения команд, размещается в том же каталоге, что и сам bat-файл;
** timeout - время в секундах;
*** c:\scripts - каталог, где предполагается разместить программу sleep.exe, bat-файл и лог-файл;

Из этого же bat-файла можно сразу после перезапуска процессов запускать скрипт бэкапа средствами 1С Предприятия. В этом случае у вас гарантированно не будет подключен ни один клиент.
Необходимая ремарка: у пользователя, под которым будет выполняться задание по перезапуску службы должны быть соответствующие права на остановку и запуск служб сервера.

 

Источники:

- материалы форума www.mista.ru;

- Документация по платформе 1С Предприятие 8.1;

- Документация по продуктам MS Windows;

См. также

PowerTools от 1 000
Внимание! Тема закрыта. Добавлять сообщения в закрытую тему запрещено.
Подписаться Добавить вознаграждение

Комментарии

1. Игорь Исхаков (Ish_2) 21.02.11 19:18
Осталась мелочь :
написать для во время выполнения каких операций перезапуск агента нежелателен.
2. Алексей С. (AlexS2) 21.02.11 19:43
В принципе, в статье упомянуто, что в рабочее время "баловаться" с перезапуском службы не рекомендуется :)
Или считаете, что этого не достаточно? :)
З.Ы. Спасибо за +
3. Ийон Тихий (cool.vlad4) 22.02.11 10:48
:D ничего против не имею...но как-то печалит постоянно снижающийся уровень статей на ИС...для того, чтобы "самому дойти" до информации в этой статье уйдет не более 5-10 минут ...
4. Игорь Исхаков (Ish_2) 22.02.11 11:08
(3) Всегда завидовал умным и проницательным.
А я вот только сейчас стал думать о том , что предложенный автором "убойный" вариант отключения всех пользователей всех баз на сервере в моём случае , возможно самый оптимальный.
5. Ийон Тихий (cool.vlad4) 22.02.11 11:27
(4) :D не знаю...офф я вот завидую людям из жарких стран ибо для меня сейчас холодильник отопительный прибор...насчет варианта в статье - это то что мне сразу в голову пришло...любой системный администратор должен знать команду net
PS добавлю, перед перезапуском советую проверять наличие сетевых соединений с сервером, а то меня как то раз чуть не убили :D ...
6. Игорь Исхаков (Ish_2) 22.02.11 12:01
(5) Так ставится цель именно отрубить всех пользователей.
7. Алексей С. (AlexS2) 22.02.11 15:16
Ish_2 пишет:

(5) Так ставится цель именно отрубить всех пользователей.

На самом деле, задача ставится несколько другая.. ))
8. Ийон Тихий (cool.vlad4) 22.02.11 15:34
Как мне казалось, делается это с целью освободить память от жестоких пыток 1С. У утечок разные причины бывают. И иногда без бубнов и танцев с перезапуском сервера 1С не получается. а чтобы пользователей отрубить - вроде средства другие. У 1С вроде параметр командной строки даже есть для этого.
9. Игорь Исхаков (Ish_2) 22.02.11 16:12
(7) Решаются две задачи : освобождение памяти и отрубить контрагентов.
Как давно и на каких конфигурациях используется такое решение ?
10. Алексей С. (AlexS2) 22.02.11 17:56
Ish_2 пишет:

(7) Решаются две задачи : освобождение памяти и отрубить контрагентов.
Как давно и на каких конфигурациях используется такое решение ?

Данное решение эксплуатируется более 3-х лет, платформа 8.1.15. Конфигурация специализированная не производства 1С, похожая на комплексную + документооборот.
Отрубить пользователей - задача вторичная, на самом деле. Первично - перезапуск службы. А отключение - просто удачный "побочный эффект". :)
11. aspirator 23 (aspirator23) 23.02.11 16:29
(8),(9),(10) А почему нельзя использовать штатный перезапуск rphost?
12. Alexander Speshilov (speshuric) 24.02.11 09:12
1. Есть штатный (1С-ный) перезапуск rphost, как уже подсказали в (11) (перезапуска rmngr и ragent нету, но и не нужно до 300-500 пользователей).
2. Перезапускать всю службу слишком жестоко.
3. Лучше не net start, а sc (если уж службу)
4. Лучше вообще не через cmd, а через VBS (с контролем соединений)
5. Поставить нормальный сервер (гигов 16-32, на крайняк 8) и 64-бит. Пусть хоть заутекается - можно спокойно решать вопросы, где утекает.
6. Найти проблему в прикладном коде из-за которой происходит утечка.
FlagmanGK; Светлый ум; Yurkiss; Fuego; +4 1 Ответить 1
13. Banderas Banderas (volsh77) 25.02.11 08:11
Юзаю, подобный перезапуск месяцев 5 :)) , нормально все, в ночное время.
14. vovchai ivanteev (vovchai) 25.02.11 09:47
вместо костыля sleep.exe можно использовать конструкцию start /wait, типа start /wait net stop "1C:Enterprise 8.2 Server Agent"
15. vovchai ivanteev (vovchai) 25.02.11 10:00
speshuric пишет:
Найти проблему в прикладном коде из-за которой происходит утечка.

в каком каком коде? предлагаете СКД переписать? у меня может пользователь закрутить типовой отчет на СКД по валовке за года два и все, сервер 8.2 сожрал >1Гб, рестарт. причем на построителе в 8.0 такого не было. в каком коде искать то проблему? да, и кстати сервер предприятия нормальный, 16 гиг ОЗУ
16. Alexander Speshilov (speshuric) 25.02.11 14:34
(15) А что на нормальном сервере делает 32-битный сервер предприятия (судя по вылету после 1 ГБ)?
Если проблема с формированием типового отчета, который возвращает немного строк, то такого происходить не должно, стоит пытаться решить проблему через v8@1c.ru - не быстро (около 2-3 месяцев, если действительно ошибка в платформе), но можно. Если отчет возвращает больше 300к-500к строк, то бить по рукам пользователей или вытаскивать "онолитегов" (если уж они так нужны) в отдельную базу (а её в отдельный процесс/кластер/службу/железку).
В большинстве случаев всё нормально находится - кто и зачем сожрал, почему не отдал, как решить или временно обойти проблему и т.п. Пожалуй, единственная действительно плохо решаемая проблема - большие и глубокие иерархические выборки, особенно если в совокупности с детализацией РН/РБ по мелким периодам.
17. vovchai ivanteev (vovchai) 25.02.11 17:43
(16) покупали с сервером под 8.0 когда 8.1 еще не вышел, а 8.2 и в помине не было. сейчас какбэ накладно покупать х64 ключ сервера предприятия (апгрейда как я знаю нет) и саму х64 ОС. проще рестарт службы делать :)

большие и глубокие иерархические выборки, особенно если в совокупности с детализацией РН/РБ по мелким периодам.

вот это как раз и присутствует (продовольственная розница с 40 тыс. элементов справочника номенклатуры) + разрезы по датам, магазинам и т.д.
завтра буду до 8.2.13.205 обновляться, посмотрим, может поможет
18. Alexander Speshilov (speshuric) 25.02.11 18:33
(17) (апгрейда как я знаю нет) - его отменили? Цены, правда, слегка поменялись, но апгрейд есть. Для совместных продуктов MS+1C сложнее, но как я помню тоже был апгрейд. Если у Вас 32-битная ОС, то вам тем более пора её апгрейднуть на 64-битную. В 32-битной ОС rphost не вылезает за 2 ГБ выделенной памяти, а в 64-битной доступно почти 4 даже без перехода на 64-битный сервер.
40к номенклатуры как бы и немного, но если это завёрнуто в 7-8 уровней иерархии и в отчет выгребается ВСЁ, то тогда конечно, поломается. Хотя я сомневаюсь, что аналитик тут что-то с отчетом сделает. Но тут проще потратить около 50000 рублей (это меньше, чем полмесяца нормального спеца в Москве, меньше, чем месяц, в других мегаполисах: спб, екб, нск) и проапгрейдить платформу и ОС.
19. aspirator 23 (aspirator23) 26.02.11 11:41
(18) А как идентифицировать причины этих вылетов? Какой отчет или хотя бы какой пользователь или его действия?
У нас больше 40 баз. Все небольшие 3-6ГБ, и пользователи(около 50) "разбросаны" по базам. Платформа 8.1
Сервер 1с 64х памяти 16 ГБ.Процессоров 8. сетевая карта 1ГБ/с.
rphost, согласно рекомендации 1с - 8штук. rphost растут, но в рамках, к обеду 0.9-1.2ГБ.
Раз в квартал сервер даже в дамп может упасть.
Технологический журнал включен. Примерно видно, когда вылетает. И примерно понятно что происходит: в CONN в этот момент виден массовый поток запросов. Но как идентифицировать кто его спровоцировал? Видны только порты через какие идут эти запросы
И странно что массовое перепроведение в одной из баз может привести к вылету других пользователей из других баз. Очевидно тут дело в каком rphost сидели эти пользователи. Гилев как-то высказывал мысль что нужен только один rphost, но без комментариев. Стремно, что при падении могут вообще все пользователи отваливаться.
Трехмесячная переписка с 1с - жевание мочала. Отправлял технологический журнал, дампы. Получил пожелания перейти на 8.2 - с предположением что возможно будет лучше.
20. Alexander Speshilov (speshuric) 26.02.11 12:04
(19) Примерно:
1. Можно попробовать сделать несколько кластеров или даже агентов (с агентами делается аналогично тому как на ИТС пишется о запинывании 1С 8.1 и 8.2 на одном сервере). А рабочих процессов - меньше (2-4-6) или столько же. Таким образом почти снимется взаимозависимость баз. С точки зрения памяти я видел rphostы и по 6 ГБ памяти съевшие - нормально работают.
2. Надеюсь СУБД на другой железке? Если на той же, то 16 ГБ - копейки. 1ГБит тоже уже не считается "много" (хотя часто и достаточно)
3. Диагностика. Рыть, рыть и еще раз рыть.
- По счетчикам производительности выявить кто тормозит: СУБД, сервер предприятия или клиент
- По полному ТЖ (блииин, какие же они ОГРООМНЫЕ) на сервере несложно понять (если получается прочитать - бугага) кто и почему порождает запросы. Ну и понятно, что дисковая подсистема уже начинает играть роль для такого режима.
- По полной трассе SQL тоже можно найти часть узких мест
В случае если узкое место сервер предприятия, то счетчики/ТЖ/ЦУП.
4. Действительно, в 1С 8.1 много проколов, которых нет в 8.2. Но в 8.2 есть зато свои проколы, которых нет в 8.1. В 8.1 мне очень не нравится:
- как работает получение списка соединений пользователей. Если оно делается программно и часто, то это ужас.
- ужасно работает получение изменений планов обмена через ВыбратьИзменения()/ПолучитьИзменение(). Да и вообще все объекты типа СправочникВыборка/ДокументВыборка ужасно работают
- мы нарвались на ппц неправильную работу "ПрекратитьРаботуСистемы"
5. Тупо прочекать, что всё свежее: драйвера (давеча на тестовом сервере неделю коллеги мучались искали проблему, оказалось драйвера необновленные), СП для ОС, СП для SQL (плюс куммулятивные обновления!). Тупо прочекать, что антивирус не мешает. Тупо прочекать, что регламенты для СУБД делаются. Тупо прочекать, что в журналах событий приложений и системы не "красно".

В общем-то скучная и будничная работа.
Yurkiss; aspirator23; +2 Ответить 1
21. aspirator 23 (aspirator23) 26.02.11 14:01
(20) На независимых форумах можно получить более квалифицированный ответ чем в 1с, где все боятся как бы чего не ляпнуть лишнего, что может повредить имиджу.
Насчет кластеров тоже стал подумывать. Даже пару сделал, переведя на них часть баз. Действительно стабильнее работают. Остальная информация тоже очень полезная - есть направление куда рыть.
22. aspirator 23 (aspirator23) 26.02.11 14:14
(20) Спасибо.
Вот эту фразу можно прокомментировать подробнее
...А рабочих процессов - меньше (2-4-6) или столько же. Таким образом почти снимется взаимозависимость баз....
Почему при малом количестве процессов снимается взаимозависимость баз? Я то думал обратное: пользователи разбросаны по процессам и если один процесс сбросит, то сбросит только "своих". Пользователи в других процессах останутся "в живых". Или имеется ввиду,то что пользователи сидят на разных кластерах?
23. Александр Крынецкий (echo77) 26.02.11 16:41
(11)(12) А можно поподробнее про штатный перезапуск 1С(перезапуск rphost)?

(0) Скрипт у вас сложный. Так обычно пишут:
net stop "Агент сервера 1С:Предприятия 8.1" && net start "Агент сервера 1С:Предприятия 8.1"

Посредине можете вставить паузу, если она вам нужна :-/
Паузу без sleep'ов делают так:
ping localhost -n <кол-во секунд> >nul
ketr; cool.vlad4; +2 Ответить 1
24. aspirator 23 (aspirator23) 26.02.11 18:40
(23) Запускаешь консоль управления сервером. Становишься на кластер. Правая кнопка мыши - свойства. Последние два поля для 8.1. Для 8.2 обрамлено в рамке.
25. Alexander Speshilov (speshuric) 26.02.11 22:20
(22)Или имеется ввиду,то что пользователи сидят на разных кластерах? - Именно. Можно даже на разных ragent.
aspirator23; +1 Ответить
26. Алексей Новоселов (a-novoselov) 30.05.11 10:00
(0) не проще "timeout /t %timeout% /nobreak >nul" вместо "c:\scripts\sleep %timeout%" использовать? тогда и в сети ничего искать/качать не прийдется.
27. Максим (Fuego) 30.05.11 11:21
а кто сказал, что 20 секунд хватит, или что вообще за определенное время служба остановится? все команды системы возвращаются сразу после отправки сервису команд start|stop. И если сервис не успевает выгрузиться и при этом получает команду start, он прекращает перезапуск. Я использовал когда-то таймаут, но это подвело меня в самый неподходящий момент. Именно поэтому я для этих целей дописал программулю, которая посылает команду службе, и дожидается, пока та выполнится. И только после этого я посылаю (в пакетном режиме) команду start. Таким образом я отключаю агент 1С:82, потом скуль (заодно - он тоже отжирает порой память), затем запускаю скуль, и запускаю 1С. Потому, что ждать пока фирма 1с соизволит исправить миллионы ошибок в коде - нет смысла. Особенно убивает, как они, не читая сообщений, отвечают шаблонными сообщениями типа "пришлите скриншоты, ничё не паняна...", а при этом всё сообщение пестрит рисунками на скриншотах как для "самых маленьких". Ща материться начну.. У меня сейчас сервер 8.2 х64 не перезапускает автоматически процессы. Не перезапускает их и при превышении объёма памяти. И я уже устал отправлять логи и картинки. Бестолково это.

// svcctrl.cpp: определяет точку входа для консольного приложения.
//

#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <aclapi.h>
#include <stdio.h>

TCHAR szCommand[10];
TCHAR szSvcName[80];

SC_HANDLE schSCManager;
SC_HANDLE schService;

VOID DisplayUsage(TCHAR *);

VOID DoStartSvc(TCHAR *);

VOID DoStopSvc(TCHAR *);

void ErrorReport(PSTR);

BOOL StopDependentServices(void);


void _tmain(int argc, TCHAR *argv[])
{
	TCHAR *compName = NULL;

    printf("\n");
    if( argc < 3 )
    {
        printf("ERROR: Incorrect number of arguments\n\n");
        DisplayUsage(argv[0]);
        return;
    }

    StringCchCopy(szCommand, 10, argv[1]);
    StringCchCopy(szSvcName, 80, argv[2]);

	if (argc = 4) 
	{
		compName = argv[3];
	}

    if (lstrcmpi( szCommand, TEXT("start")) == 0 )
        DoStartSvc(compName);
    else if (lstrcmpi( szCommand, TEXT("stop")) == 0 )
        DoStopSvc(compName);
    else 
    {
        _tprintf(TEXT("Unknown command (%s)\n\n"), szCommand);
        DisplayUsage(argv[0]);
    }
}



void ErrorReport(CHAR *lpszFunction) 
{ 
    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError(); 

	FormatMessageA(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPSTR) &lpMsgBuf,
        0, NULL );

    // Display the error message and exit the process

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
		(lstrlenA((LPCSTR)lpMsgBuf)+lstrlenA((LPSTR)lpszFunction)+40)*sizeof(CHAR)); 
	StringCchPrintfA((LPSTR)lpDisplayBuf, 
        LocalSize(lpDisplayBuf) / sizeof(CHAR),
        "%s failed with error code %d: %s", 
        lpszFunction, dw, lpMsgBuf); 

	CharToOemA((CHAR*)lpDisplayBuf,(CHAR*)lpDisplayBuf);

	printf((CHAR*)lpDisplayBuf); 

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
}

VOID DisplayUsage(TCHAR *pn)
{
    printf("Description:\n");
    printf("\tCommand-line tool that controls a service.\n\n");
    printf("Usage:\n");
	printf("\t %S [command] [service_name] {[computer]}\n\n", pn);
    printf("\t[command]\n");
    printf("\t  start\n");
    printf("\t  stop\n");
}

//
// Purpose: 
//   Starts the service.
//
// Parameters:
//   None
// 
// Return value:
//   None
//

VOID DoStartSvc(TCHAR *compName)
{
    SERVICE_STATUS_PROCESS ssStatus; 
    DWORD dwOldCheckPoint; 
    DWORD dwStartTickCount;
    DWORD dwWaitTime;
    DWORD dwBytesNeeded;

    // Get a handle to the SCM database. 
 
    schSCManager = OpenSCManager( 
        compName,                    // local computer
        NULL,                    // ServicesActive database 
        SC_MANAGER_ALL_ACCESS);  // full access rights 
 
    if (NULL == schSCManager) 
    {
        //printf("OpenSCManager failed (%d)\n", GetLastError());
		ErrorReport("OpenSCManager");
        return;
    }

    // Get a handle to the service

    schService = OpenService( 
        schSCManager,         // SCM database 
        szSvcName,            // name of service 
        SERVICE_ALL_ACCESS);  // full access 
 
    if (schService == NULL)
    { 
        //printf("OpenService failed (%d)\n", GetLastError()); 
		ErrorReport("OpenService");
        CloseServiceHandle(schSCManager);
        return;
    }    

    // Attempt to start the service.

    if (!StartService(
            schService,  // handle to service 
            0,           // number of arguments 
            NULL) )      // no arguments 
    {
        //printf("StartService failed (%d)\n", GetLastError());
		ErrorReport("StartService");
        CloseServiceHandle(schService); 
        CloseServiceHandle(schSCManager);
        return; 
    }
    else printf("Service start pending...\n"); 

    // Check the status until the service is no longer start pending. 
 
    if (!QueryServiceStatusEx( 
            schService,             // handle to service 
            SC_STATUS_PROCESS_INFO, // info level
            (LPBYTE) &ssStatus,             // address of structure
            sizeof(SERVICE_STATUS_PROCESS), // size of structure
            &dwBytesNeeded ) )              // if buffer too small
    {
        return; 
    }
 
    // Save the tick count and initial checkpoint.

    dwStartTickCount = GetTickCount();
    dwOldCheckPoint = ssStatus.dwCheckPoint;

    while (ssStatus.dwCurrentState == SERVICE_START_PENDING) 
    { 
        // Do not wait longer than the wait hint. A good interval is 
        // one-tenth the wait hint, but no less than 1 second and no 
        // more than 10 seconds. 
 
        dwWaitTime = ssStatus.dwWaitHint / 10;

        if( dwWaitTime < 1000 )
            dwWaitTime = 1000;
        else if ( dwWaitTime > 10000 )
            dwWaitTime = 10000;

        Sleep( dwWaitTime );

        // Check the status again. 
 
        if (!QueryServiceStatusEx( 
            schService,             // handle to service 
            SC_STATUS_PROCESS_INFO, // info level
            (LPBYTE) &ssStatus,             // address of structure
            sizeof(SERVICE_STATUS_PROCESS), // size of structure
            &dwBytesNeeded ) )              // if buffer too small
            break; 
 
        if ( ssStatus.dwCheckPoint > dwOldCheckPoint )
        {
            // The service is making progress.

            dwStartTickCount = GetTickCount();
            dwOldCheckPoint = ssStatus.dwCheckPoint;
        }
        else
        {
            if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint)
            {
                // No progress made within the wait hint.
                break;
            }
        }
    } 

    // Determine whether the service is running.

    if (ssStatus.dwCurrentState == SERVICE_RUNNING) 
    {
        printf("Service started successfully.\n"); 
    }
    else 
    { 
        printf("Service not started. \n");
        printf("  Current State: %d\n", ssStatus.dwCurrentState); 
        printf("  Exit Code: %d\n", ssStatus.dwWin32ExitCode); 
        printf("  Check Point: %d\n", ssStatus.dwCheckPoint); 
        printf("  Wait Hint: %d\n", ssStatus.dwWaitHint); 
    } 

    CloseServiceHandle(schService); 
    CloseServiceHandle(schSCManager);
}



//
// Purpose: 
//   Stops the service.
//
// Parameters:
//   None
// 
// Return value:
//   None
//
VOID DoStopSvc(TCHAR *compName)
{
    SERVICE_STATUS_PROCESS ssp;
    DWORD dwStartTime = GetTickCount();
    DWORD dwBytesNeeded;
    DWORD dwTimeout = 120000; // 2-minutes time-out

    // Get a handle to the SCM database. 
 
    schSCManager = OpenSCManager( 
        compName,                    // local computer
        NULL,                    // ServicesActive database 
        SC_MANAGER_ALL_ACCESS);  // full access rights 
 
    if (NULL == schSCManager) 
    {
        //printf("OpenSCManager failed (%d)\n", GetLastError());
		ErrorReport("OpenSCManager");
        return;
    }

    // Get a handle to the service.

    schService = OpenService( 
        schSCManager,         // SCM database 
        szSvcName,            // name of service 
        SERVICE_STOP | 
        SERVICE_QUERY_STATUS | 
        SERVICE_ENUMERATE_DEPENDENTS);  
 
    if (schService == NULL)
    { 
        //printf("OpenService failed (%d)\n", GetLastError()); 
		ErrorReport("OpenService");
        CloseServiceHandle(schSCManager);
        return;
    }    

    // Make sure the service is not already stopped.

    if ( !QueryServiceStatusEx( 
            schService, 
            SC_STATUS_PROCESS_INFO,
            (LPBYTE)&ssp, 
            sizeof(SERVICE_STATUS_PROCESS),
            &dwBytesNeeded ) )
    {
        //printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
		ErrorReport("QueryServiceStatusEx");
        goto stop_cleanup;
    }

    if ( ssp.dwCurrentState == SERVICE_STOPPED )
    {
        printf("Service is already stopped.\n");
        return;
    }

    // If a stop is pending, wait for it.

    while ( ssp.dwCurrentState == SERVICE_STOP_PENDING ) 
    {
        printf("Service stop pending...\n");
        Sleep( ssp.dwWaitHint );
        if ( !QueryServiceStatusEx( 
                 schService, 
                 SC_STATUS_PROCESS_INFO,
                 (LPBYTE)&ssp, 
                 sizeof(SERVICE_STATUS_PROCESS),
                 &dwBytesNeeded ) )
        {
           // printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
			ErrorReport("QueryServiceStatusEx");
            goto stop_cleanup;
        }

        if ( ssp.dwCurrentState == SERVICE_STOPPED )
        {
            printf("Service stopped successfully.\n");
            goto stop_cleanup;
        }

        if ( GetTickCount() - dwStartTime > dwTimeout )
        {
            printf("Service stop timed out.\n");
            goto stop_cleanup;
        }
    }

    // If the service is running, dependencies must be stopped first.

    StopDependentServices();

    // Send a stop code to the service.

    if ( !ControlService( 
            schService, 
            SERVICE_CONTROL_STOP, 
            (LPSERVICE_STATUS) &ssp ) )
    {
        //printf( "ControlService failed (%d)\n", GetLastError() );
		ErrorReport("ControlService");
        goto stop_cleanup;
    }

    // Wait for the service to stop.

    while ( ssp.dwCurrentState != SERVICE_STOPPED ) 
    {
        Sleep( ssp.dwWaitHint );
        if ( !QueryServiceStatusEx( 
                schService, 
                SC_STATUS_PROCESS_INFO,
                (LPBYTE)&ssp, 
                sizeof(SERVICE_STATUS_PROCESS),
                &dwBytesNeeded ) )
        {
            //printf( "QueryServiceStatusEx failed (%d)\n", GetLastError() );
			ErrorReport("QueryServiceStatusEx");
            goto stop_cleanup;
        }

        if ( ssp.dwCurrentState == SERVICE_STOPPED )
            break;

        if ( GetTickCount() - dwStartTime > dwTimeout )
        {
            printf( "Wait timed out\n" );
            goto stop_cleanup;
        }
    }
    printf("Service stopped successfully\n");

stop_cleanup:
    CloseServiceHandle(schService); 
    CloseServiceHandle(schSCManager);
}

BOOL StopDependentServices()
{
    DWORD i;
    DWORD dwBytesNeeded;
    DWORD dwCount;

    LPENUM_SERVICE_STATUS   lpDependencies = NULL;
    ENUM_SERVICE_STATUS     ess;
    SC_HANDLE               hDepService;
    SERVICE_STATUS_PROCESS  ssp;

    DWORD dwStartTime = GetTickCount();
    DWORD dwTimeout = 30000; // 30-second time-out

    // Pass a zero-length buffer to get the required buffer size.
    if ( EnumDependentServices( schService, SERVICE_ACTIVE, 
         lpDependencies, 0, &dwBytesNeeded, &dwCount ) ) 
    {
         // If the Enum call succeeds, then there are no dependent
         // services, so do nothing.
         return TRUE;
    } 
    else 
    {
        if ( GetLastError() != ERROR_MORE_DATA )
            return FALSE; // Unexpected error

        // Allocate a buffer for the dependencies.
        lpDependencies = (LPENUM_SERVICE_STATUS) HeapAlloc( 
            GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytesNeeded );
  
        if ( !lpDependencies )
            return FALSE;

        __try {
            // Enumerate the dependencies.
            if ( !EnumDependentServices( schService, SERVICE_ACTIVE, 
                lpDependencies, dwBytesNeeded, &dwBytesNeeded,
                &dwCount ) )
            return FALSE;

            for ( i = 0; i < dwCount; i++ ) 
            {
                ess = *(lpDependencies + i);
                // Open the service.
                hDepService = OpenService( schSCManager, 
                   ess.lpServiceName, 
                   SERVICE_STOP | SERVICE_QUERY_STATUS );

                if ( !hDepService )
                   return FALSE;

                __try {
                    // Send a stop code.
                    if ( !ControlService( hDepService, 
                            SERVICE_CONTROL_STOP,
                            (LPSERVICE_STATUS) &ssp ) )
                    return FALSE;

                    // Wait for the service to stop.
                    while ( ssp.dwCurrentState != SERVICE_STOPPED ) 
                    {
                        Sleep( ssp.dwWaitHint );
                        if ( !QueryServiceStatusEx( 
                                hDepService, 
                                SC_STATUS_PROCESS_INFO,
                                (LPBYTE)&ssp, 
                                sizeof(SERVICE_STATUS_PROCESS),
                                &dwBytesNeeded ) )
                        return FALSE;

                        if ( ssp.dwCurrentState == SERVICE_STOPPED )
                            break;

                        if ( GetTickCount() - dwStartTime > dwTimeout )
                            return FALSE;
                    }
                } 
                __finally 
                {
                    // Always release the service handle.
                    CloseServiceHandle( hDepService );
                }
            }
        } 
        __finally 
        {
            // Always free the enumeration buffer.
            HeapFree( GetProcessHeap(), 0, lpDependencies );
        }
    } 
    return TRUE;
}


...Показать Скрыть
Skaredov; evita; cool.vlad4; +3 Ответить 1
28. Alex Tim (Qseft) 05.10.11 16:27
(27) Спасибо за скрипт, еще бы добавить принудительный kill процессов rphost по таймауту.
29. Елена (elena_77) 26.01.12 11:26
Спасибо за скрипт. У нас постоянно зависают сеансы на сервере и ключей не хватает тогда. Пока спасаемся только перезапуском службы Агент серсера 1С. Пришли к тому, что необходимо ночью регулярно перезапускать службу.
30. Oleg karp (Oleg1708) 15.03.12 16:08
У нас и 81 не глючил и 82... Странно
31. Сергей Соловьев (sergey_s_) 17.10.12 05:58
А в настройках кластера 1541 перезапуск рабочего процесса для чего?
32. Сергей Соловьев (sergey_s_) 24.10.12 09:10
33. Алексей С. (AlexS2) 24.10.12 10:43
(31) sergey_s_, Я прошу прощения, Вы статью читали?
34. Константин (maverick76) 11.02.13 09:29
Пользуюсь автоматическим перезапуском сервера 1С
35. Никита Коротаев (bforce) 11.02.13 09:50
Я тоже пользую типовой перезапуск процессов и по времени, и при превышении объемов памяти (8.2.15, 8.2.16, 8.2.17). Проблем не вижу.