К сожалению, это все еще факт, что наши игровые хостинговые машины иногда нуждаются в перезагрузке, и это в большей степени относится к машинам с Windows, чем к любым другим. Обновления Windows часто требуют перезапуска компьютера, и вы можете сделать очень много вещей, чтобы смягчить это. В конечном итоге перезапуски неизбежны, и лучше закончить их раньше, чем позже, вместо того, чтобы откладывать его и оставлять систему без исправлений и под угрозой.

Итак, когда обновление Windows хочет автоматически выключить систему, что вы делаете? Просто позволить этому случиться - не вариант - что, если игроки играют в игры на серверах, работающих на этой машине? Простое исчезновение серверов было бы ужасным для пользователя, и это без учета проблемы файлов сохранения на стороне сервера. Что произойдет в играх, в которых хранятся данные об игроках или игровом мире, если эти серверы просто отключатся? Он поврежден? Если не прекратить полностью, рискуют ли игроки потерять все, над чем они работали? В некоторых случаях ответ - да, да, и это недопустимо.

Итак, что вы можете с этим поделать?

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

Clanforge управляет каждым процессом игрового сервера на машине, и эта система управления знает подробности о каждой игре и о том, требует ли она особого обращения. Уровень управления останавливает каждый сервер, используя соответствующие протоколы удаленной консоли, чтобы отправлять сообщения игрокам, выгружать их и запускать сохранение сервера перед завершением процессов. Но все это бесполезно, если мы не сможем сделать все это до того, как Windows решит просто убить все процессы и завершить работу. Так начинается наше путешествие по кроличьей норе процесса завершения работы Windows ...

Что происходит, когда Windows выключается

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

Суть процесса заключается в том, что, во-первых, все процессы, запущенные в интерактивном сеансе, завершаются в порядке, обратном их приоритету завершения (сначала номер с наивысшим приоритетом). Завершение проверяет, что это за процесс (консольное приложение, графический интерфейс с окном верхнего уровня, служба) и отправляет ему событие, ожидая ответа, чтобы узнать, может ли он продолжить процесс завершения работы. Если он не получает ответа или запрос Windows подождать, он ждет в течение периода времени, указанного в разделе реестра (разные ключи в зависимости от типа процесса). После того, как все в этом списке было успешно завершено, мы переходим к процессам в сеансе 0 - здесь находятся системные службы.

Службы контролируются SCM (диспетчер управления службами), и SCM сначала отправляет уведомления перед выключением, которые позволяют службам блокировать процесс выключения почти на неопределенный срок, а затем останавливают запросы к службам в порядке зависимости. Он ожидает, пока службы сообщат об остановке, или просто завершает их работу, если они превышают тайм-аут.

Так в чем проблема?

Что ж, все службы, которые запускают игровые серверы и управляют ими, являются службами. Это означает, что они запускаются в сеансе 0 и завершаются последними - звучит хорошо, не так ли?

Неправильный. Потому что наши службы управления запускают реальные игры в интерактивном сеансе. Почему? Потому что многие игровые серверы предполагают, что они запускаются на обычном интерактивном рабочем столе, и ломаются ужасным, жутким образом, когда вы поступаете иначе. Это означает, что Windows вытаскивает почву из-под служб управления, прежде чем сможет что-либо сделать - серверы будут убиты еще до того, как управляющая ими служба даже узнает, что именно произошло. Немного больно, если не сказать больше.

Так как же обойтись без подобных проблем? Что ж, есть несколько вариантов, все со своими достоинствами и недостатками:

  1. Предотвратить завершение работы вообще - в основном отключите службы, которые вызывают завершение работы, и вручную выполняйте обновления Windows с помощью собственной запланированной задачи.
  2. Определить, когда запрашивается выключение, отменить его, правильно выключить серверы, а затем запустить новое выключение
  3. Заблокируйте завершение работы с помощью различных доступных для этого методов и используйте метод, который обнаруживает запрос на отключение и аккуратно завершает работу серверов, а затем позволяет продолжить процесс завершения работы.
  4. Не запускайте средства управления как службу сеанса 0, дайте ему огромный приоритет завершения и заставьте его обрабатывать собственное завершение, чисто отключая серверы, которыми он управляет.

Вариант 1 немного радикален, и лично мне он не очень нравится. Отключение автоматических обновлений кажется грязным и опасным, что для многих людей прямо на улице, но для машин, на которых размещены игровые серверы, не так. Если ваш собственный планировщик по какой-то причине выходит из строя (например, мошенническое обновление Windows решает удалить / сбросить ваши запланированные задачи) или служба обновлений Windows повторно включается, значит, для вас плохое время. Кроме того, запуск обновлений Windows вручную просто кажется менее безопасным, чем позволить службе управлять им, из-за возможности опоздания с применением критических или аварийных исправлений. Это также означает исключение возможности делать что-то приятное для ваших пользователей, например, применять обновления и перезагружаться только тогда, когда в сети нет игроков, поскольку это просто глупая запланированная задача - если вы не создадите отдельную систему для обнаружения этих событий и соответствующего планирования действий.

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

Вариант 3 в некоторой степени похож на Вариант 2, но вместо того, чтобы реагировать на текущее завершение работы и отменять его, мы вместо этого используем вызов ShutdownBlockReasonCreate Windows для регистрации блокировки процедуры завершения работы сразу после запуска нашей службы. Однако мы не можем сделать это в службе, нам нужен процесс со скрытым окном, работающий в интерактивном сеансе, чтобы получить событие WM_QUERYENDSESSION, и поэтому блок должен быть там. Когда мы получаем это событие, мы можем затем запустить службу для правильного завершения работы всех серверов, а когда она завершится, дождаться сообщения от нее, чтобы сообщить нашему фиктивному процессу блокировки отменить блокировку с помощью ShutdownBlockReasonDestroy и выйти.

Вариант 4 лишает нас каких-либо преимуществ использования системы управления службами Windows (управление зависимостями, удаленное управление и ведение журнала событий). Однако во многих отношениях он решает множество проблем, которые необходимо обойти (например, необходимость олицетворять текущего пользователя, чтобы запустить серверные процессы в интерактивный сеанс). Это означает, что необходимо изменить способ запуска служб, используя запланированные задачи или просто функцию автозапуска / запуска в Windows, чтобы службы запускались при входе в систему, но с этим легко справиться. Отсутствие работы в качестве службы означает, что мы можем выполнять все действия по блокировке выключения из вариантов 2 и 3, но нам не нужен дополнительный вспомогательный процесс, поскольку наши процессы управления могут использовать их напрямую.

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

Мы все еще находимся в процессе оценки, экспериментируем с несколькими вариантами, пока не остановимся на одном, который лучше всего вписывается в долгосрочный план управления и автоматизации. Учитывая все плюсы и минусы каждого из них, нам предстоит еще много испытаний! В частности, хостинг игровых серверов - сложный зверь; у вас нет никакого контроля над тем, как на самом деле работает серверный код, и вы имеете ряд жестких ограничений (производительность, ОС, время безотказной работы и т. д.). Для вашего собственного варианта использования ответы могут быть более четкими.