Веб-сервер Graceful shutdown
Graceful shutdown — это механизм, который позволяет завершать работу веб-сервера без потери необработанных запросов и неожиданного прекращения сессии.
Сигналы операционной системы
Для начала ознакомимся с информацией о сигналах в операционных системах семейства Unix.
В этих операционных системах существует множество сигналов, которые могут быть посланы процессу для обработки. Рассмотрим некоторые из самых распространенных.
SIGHUP (1): сигнал, который посылается процессу, когда его терминал закрывается. Обычно используется для перезапуска или перезагрузки конфигурационного файла.
SIGINT (2): сигнал, который посылается процессу, когда пользователь нажимает Ctrl+C в терминале. Обычно используется для завершения процесса.
SIGKILL (9): сигнал, который посылается процессу для его немедленного завершения. Этот сигнал не может быть обработан или проигнорирован процессом.
SIGTERM (15): сигнал, который посылается процессу для его завершения. Этот сигнал может быть обработан или проигнорирован процессом, но обычно используется для его корректного завершения, например для закрытия файловых дескрипторов или освобождения памяти.
SIGSTOP (19) и SIGCONT (18): сигналы, которые можно использовать для остановки и продолжения процесса соответственно. Они не могут быть обработаны или проигнорированы процессом.
Это лишь несколько примеров сигналов, которые используются в операционных системах семейства Unix.
Кроме того, в Unix-подобных операционных системах существует возможность отправлять сигналы по идентификатору процесса (PID) или по имени процесса. Для этого можно использовать утилиты типа kill, killall, pkill и др.
Также некоторые сигналы могут быть проигнорированы или переопределены процессом с использованием функций signal() или sigaction(). Это позволяет процессу обрабатывать их заданным образом.
Сигналы являются важным механизмом управления процессами в операционных системах семейства Unix. Они могут использоваться для завершения, остановки, продолжения или перезапуска процессов, а также для обработки специфических ситуаций и событий в процессе.
Сигнал sigterm
Sigterm (сигнал завершения) используется для корректного завершения процесса, например для закрытия файловых дескрипторов или освобождения памяти.
В терминале сигнал sigterm может быть отправлен процессу с помощью утилит kill или pkill, которые принимают PID процесса или его имя как аргумент. Например, чтобы отправить сигнал sigterm процессу с PID 123, можно использовать команду:
kill -15 123
В Go это может быть сделано с использованием пакета context. Твой код должен слушать сигналы для начала завершения работы и закрывать соединения с клиентами по мере их завершения.
Если процесс не обрабатывает сигнал sigterm или не завершается в течение некоторого времени, то может быть отправлен сигнал sigkill для немедленного завершения процесса.
Важно заметить, что некоторые процессы могут быть настроены на игнорирование сигнала sigterm или обработку его особым способом, и в этом случае он может не завершить процесс. Здесь может быть использован другой способ: завершить процесс можно, например, программно, через API или интерфейс процесса.
Простой способ вызвать сигнал sigterm — нажать сочетание клавиш CTRL+C в терминале при запущенном процессе.
Пример кода, который демонстрирует реализацию graceful shutdown для веб-сервера на Go, ты найдешь по ссылке.
В данном примере сначала мы создаем экземпляр http.Server с настройкой адреса и функцией обработчика. Затем запускаем сервер в отдельной горутине с помощью srv.ListenAndServe(). Далее слушаем сигнал от ОС для начала завершения работы сервера. Когда сигнал получен, мы устанавливаем тайм-аут для завершения работы сервера с помощью srv.Shutdown(ctx).
Этот код позволяет серверу завершить работу над всеми необработанными запросами и отключиться от клиентов в безопасном режиме.
Важно отметить, что в данном примере мы установили тайм-аут 5 секунд для завершения работы сервера. В реальном проекте ты можешь настроить этот тайм-аут на основе своих конкретных требований: это может быть, например, максимальное время для завершения всех запросов или минимальное время для завершения новых запросов.
Кроме того, важно обрабатывать ошибки, которые могут возникнуть при завершении работы сервера, такие как недостаток ресурсов или невозможность соединения с клиентом.