Як служба Windows може програмно перезапуститись?


135

Мені потрібно написати надійний код у .NET, щоб служба Windows (сервер 2003) перезапустилася. Який найкращий спосіб зробити це? Чи є якийсь .NET API для цього?


7
"Надійна" - це непомітне слово ( stackoverflow.fogbugz.com/default.asp?W13086 ) - які конкретні риси вам потрібні?
Айдан Раян

Відповіді:


187

Встановіть перезапуск служби після відмови (двічі клацніть службу на панелі керування та огляньте їх на цих вкладках - я забув її назву). Потім, коли ви хочете, щоб послуга перезапустилася, просто зателефонуйте Environment.Exit(1)(або будь-яке ненульове повернення), і ОС перезапустить її для вас.


7
Знайдіть місцезнаходження на панелі послуг, клацніть правою кнопкою миші відповідну послугу та виберіть властивості, а потім виберіть вкладку відновлення.
Джеймс Майкл Заєць

20
Я бачу, як це домагається бажаної поведінки, але зворотний код 1 має на меті сказати системі, що сталася помилка. Це не погана практика, якщо насправді помилок не було, і ви просто хотіли перезапустити службу?
mgttlinger

4
Це може зробити програматично інсталятор служби у події після установки, не потрібно клацати ... Що робити, якщо ваша служба знаходиться на віддаленому сервері, і вам потрібно встановити її кілька разів на день, наприклад, під час тестування?
Дін Куга

5
@mgttlinger: Я думаю, що так, це погана практика, коли ваша послуга є здоровою, тому її ніколи не потрібно буде перезапускати. Але деякі архітектури сервісів недоступні, і якщо їх потрібно перезапустити, це симптом, що це не так добре, тому немає проблем закрити та звільнити деякі мінімальні курорти (якщо можливо) та "порізати ноги", залишивши неналежна робота служби може бути гіршою (марною).
Лучано

5
@JohnLeidegren, якщо ви хочете належного відключення, ви можете встановити, Service.ExitCode = 1а потім виконати, Service.Stop()а також включити прапорець "Увімкнути дії для зупинок з помилками" на екрані налаштування відновлення служби. Це робиться таким чином, забезпечує належне відключення і все ще викликає перезапуск.
Кріс Райс

22
Dim proc As New Process()
Dim psi As New ProcessStartInfo()

psi.CreateNoWindow = True
psi.FileName = "cmd.exe"
psi.Arguments = "/C net stop YOURSERVICENAMEHERE && net start YOURSERVICENAMEHERE"
psi.LoadUserProfile = False
psi.UseShellExecute = False
psi.WindowStyle = ProcessWindowStyle.Hidden
proc.StartInfo = psi
proc.Start()

3
Не забудьте додати назву "" навколо вас, якщо вона містить пробіли.
apc

4
Це стосується лише служб, що працюють під привілейованим обліковим записом, але це все одно погано.
Дмитро Гусаров

17

Ви не можете бути впевнені, що обліковий запис користувача, під яким працює ваша служба, має навіть дозволи зупинити та перезапустити службу.


Хоча + 1-ed, коли я стикався з тією ж проблемою, при перегляді sc.exe виявляється, що він використовує SERVICE_QUERY_CONFIG як dwDesiredAccess при виклику OpenSCManager (), а потім викликає OpenService () за допомогою SERVICE_START | SERVICE_STOP для відкриття певної послуги, і вона працює добре (немає проблем з доступом). Не знаєте, як це можна зробити в .NET.
n0p

Більшість служб Windows працює як Система, тому це не повинно бути проблемою.
Переключитись

@Switch існує величезне коло сервісів, які працюють під послугою NETWORK SERVICE, які за замовчуванням навіть не мають права відкривати власний виконуваний файл.
AgentFire

@AgentFire, правильно, але за замовчуванням це локальна система, а не мережева служба. Локальна система по суті має найвищий рівень привілеїв для операційної системи - перевищує ті, що присвоєні членам місцевої групи адміністраторів.
Переключити

@Switch, але використання найбільш доступних привілеїв є порушенням принципу PoL .
AgentFire

12

Ви можете створити процес, який є командним рядком DOS, який перезавантажиться самостійно:

 Process process = new Process();
 process.StartInfo.FileName = "cmd";
 process.StartInfo.Arguments = "/c net stop \"servicename\" & net start \"servicename\"";
 process.Start();

Це, не роблячи нічого іншого, успадкує контекст безпеки виклику потоку ... і доки це контекст, у якого є достатня кількість кінських сил, щоб перезапустити, ви добре.
Глина

12
const string strCmdText = "/C net stop \"SERVICENAME\"&net start \"SERVICENAME\"";
Process.Start("CMD.exe", strCmdText);

де SERVICENAMEназва вашого сервісу (подвійні лапки, включені до облікового запису пробілів у назві послуги, інакше не можна).

Очистити, конфігурація автоматичного перезавантаження не потрібна.


9
дізнався щось нове про & vs &&: [command1] & [command2] завжди буде виконувати обидві команди послідовно, тоді як [command1] && [command2] запускає command2, тільки якщо command1 працює успішно ( autoitscript.com/forum/topic/… )
Джефрі Лицар

5

Це залежало б від того, чому ви хочете, щоб він перезапустився.

Якщо ви просто шукаєте спосіб періодично очищати службу, у вас може працювати таймер, який періодично викликає процедуру очищення.

Якщо ви шукаєте спосіб перезапустити при відмові - сам хост сервісу може надати таку можливість під час налаштування.

То чому вам потрібно перезапустити сервер? Чого ви намагаєтесь досягти?


1
Це не спрацює, якщо ви переймаєтесь великою купою об’єктів та пам’яттю. Нібито. NET 4 / 4.5 і 64-бітні процеси багато в цьому допомогли.
Девід Касса

3

Я не думаю, що можна скористатися автономною службою (коли ви зателефонуєте Перезапустити, вона зупинить службу, яка перерве команду Перезавантаження, і вона ніколи не запуститься знову). Якщо ви можете додати другий .exe (додаток консолі, що використовує клас ServiceManager), ви можете вимкнути автономний файл .exe і перезапустити його, а потім вийти.

По-друге, ви, ймовірно, могли б змусити службу зареєструвати заплановану задачу (наприклад, використовуючи командний рядок команди «at»), щоб запустити службу, а потім змусити її зупинитись; це, мабуть, спрацює.


3

Проблема з обшивкою пакетного файлу або EXE полягає в тому, що служба може мати або не мати дозволів, необхідних для запуску зовнішньої програми.

Найчистіший спосіб зробити це, що я знайшов, - це використовувати метод OnStop (), який є вхідною точкою для диспетчера служб управління. Тоді весь ваш код очищення запуститься, і ви не матимете підвісних сокет або інших процесів, якщо ваш стоп-код виконує свою роботу.

Для цього вам потрібно встановити прапор перед тим, як скасувати, який повідомляє методу OnStop вийти з кодом помилки; тоді SCM знає, що послугу потрібно перезапустити. Без цього прапора ви не зможете зупинити послугу вручну з SCM. Це також передбачає, що ви налаштували службу для перезавантаження з помилкою.

Ось мій стоп-код:

...

bool ABORT;

protected override void OnStop()
{
    Logger.log("Stopping service");
    WorkThreadRun = false;
    WorkThread.Join();
    Logger.stop();
    // if there was a problem, set an exit error code
    // so the service manager will restart this
    if(ABORT)Environment.Exit(1);
}

Якщо служба стикається з проблемою і потребує перезавантаження, я запускаю потік, який зупиняє службу з SCM. Це дозволяє службі прибирати після себе:

...

if(NeedToRestart)
{
    ABORT = true;
    new Thread(RestartThread).Start();
}

void RestartThread()
{
    ServiceController sc = new ServiceController(ServiceName);
    try
    {
        sc.Stop();
    }
    catch (Exception) { }
}

2

Я б використовував Планувальник Windows для планування перезавантаження вашої служби. Проблема полягає в тому, що ви не можете перезапустити себе, але можете зупинити себе. (Ви, по суті, відпиляли гілку, на якій сидите ... якщо ви отримаєте мою аналогію) Вам потрібен окремий процес, щоб зробити це за вас. Планувальник Windows - це відповідний. Сплануйте одноразове завдання, щоб перезапустити службу (навіть із самої служби), щоб її виконати негайно.

В іншому випадку вам доведеться створити процес «вівчарства», який робить це за вас.


2

Перша відповідь на питання - це найпростіше рішення: "Environment.Exit (1)" Я використовую це на Windows Server 2008 R2, і він працює чудово. Послуга припиняється, O / S чекає 1 хвилину, після чого перезапускає її.


Скільки часу він чекає, залежить від того, як довго ви налаштуєте його чекати. Типово - 1 хвилина, але якщо хтось не хоче, що ваша відповідь справить неправильне враження.
Еспен

1

Я не думаю, що це може. Коли послуга "зупинена", вона повністю завантажується.

Що ж, гаразд, завжди є спосіб, який я думаю. Наприклад, ви можете створити відокремлений процес, щоб зупинити послугу, потім перезапустити її та вийти.


0

Кращим підходом може бути використання служби NT в якості обгортки для вашої програми. Коли запускається служба NT, ваша програма може запускатися в режимі очікування, очікуючи запуску команди (або налаштовується на автоматичний запуск).

Подумайте про машину, коли вона запущена, вона починається в режимі очікування, чекаючи, коли ваша команда рухатиметься вперед або назад. Це також дозволяє отримати інші переваги, наприклад, краще віддалене адміністрування, оскільки ви можете вибрати, як виставити заявку.


0

Тільки проходячи: і подумав, що я додам додаткову інформацію ...

Ви також можете кинути виняток, це автоматично закриє службу Windows, а параметри автоматичного перезапуску просто запускаються. Єдине питання з цього полягає в тому, що якщо у вас на комп’ютері є середовище dev, тоді JIT намагається запустити, і ви отримаєте підказку про налагодження Y / N. скажіть ні, тоді воно закриється, а потім перезапустіть належним чином. (на ПК без JIT це все працює). причина ім тролінгу, це JIT є новим для Win 7 (він працював нормально з XP тощо), і я намагаюся знайти спосіб відключення JIT .... я можу спробувати метод Environment.Exit, згаданий тут, дивіться, як це теж працює.

Крістіан: Брістоль, Великобританія


3
Усі ці винятки для викидання, рішення exit (1) уникають належної очищення програми.
Незграбний

0

Створіть файл restart.bat таким чином

@echo on
set once="C:\Program Files\MyService\once.bat"
set taskname=Restart_MyService
set service=MyService
echo rem %time% >%once%
echo net stop %service% >>%once%
echo net start %service% >>%once%
echo del %once% >>%once%

schtasks /create /ru "System" /tn %taskname% /tr '%once%' /sc onstart /F /V1 /Z
schtasks /run /tn %taskname%

Потім видаліть завдання% taskname%, коли запуститься% service%


0

Створіть окремий додаток для розміщення коду програми. Коли потрібен перезапуск, ми можемо вивантажити та перезавантажити додаток замість процесу (служба Windows). Ось як працює пул додатків IIS, вони не запускають додаток asp.net безпосередньо, вони використовують окрему програму appdmain.


-2

Найпростіший спосіб - мати пакетний файл із:

net stop net start

і додайте файл до планувальника з потрібним інтервалом часу


Це не працює, тому що пакет зупиняється між обома командами, оскільки це дочірній процес самої служби.
Orabîg

-3
private static void  RestartService(string serviceName)
    {
        using (var controller = new ServiceController(serviceName))
        {
            controller.Stop();
            int counter = 0;
            while (controller.Status != ServiceControllerStatus.Stopped)
            {
                Thread.Sleep(100);
                controller.Refresh();
                counter++;
                if (counter > 1000)
                {
                    throw new System.TimeoutException(string.Format("Could not stop service: {0}", Constants.Series6Service.WindowsServiceName));
                }
            }

            controller.Start();
        }
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.