Отправить пользовательский сигнал процессу Curreng Golang - PullRequest
0 голосов
/ 05 мая 2019

Я создаю HTTP-сервер, используя Go.И всякий раз, когда я работаю над обслуживанием базы данных, я хочу, чтобы сервер перенаправлял весь трафик на страницу «текущая работа по обслуживанию».

В настоящее время это делается секретной страницей администратора (например, http://myhome/secret), но мне интересно, можно ли это сделать с помощью сигнала, аналогичного сигналу TERM, но временно перенаправить, а не завершитьprocess.

Например.

/home/myhome> nohup startServer &
... 
/home/myhome> changeMyServerStatus "maintenance"

Я предполагаю, что будет два исполняемых файла .. "startServer" и "changeMyServerStatus"

Таким образом, это похоже на службу.(вроде перезагрузки) Но возможно ли это? Если да, то можете ли вы дать мне подсказку, пожалуйста?

Спасибо

1 Ответ

3 голосов
/ 06 мая 2019

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

Вы можете использовать стандартные пользовательские сигналы : SIGUSR1 для включения обслуживания и SIGUSR2 для его отключения.

Используйте os/signal, чтобы получать уведомления об этих сигналах и обновлять состояние программы:

// Brief example code. Real code might be structured differently
// (perhaps pack up maint and http.Server in one type MyServer).

var maint uint32 // atomic: 1 if in maintenance mode

func handleMaintSignals() {
    ch := make(chan os.Signal, 1)
    go func() { // FIXME: use Server.RegisterOnShutdown to terminate this
        for sig := range ch {
            switch sig { // FIXME: add logging
            case syscall.SIGUSR1:
                atomic.StoreUint32(&maint, 1)
            case syscall.SIGUSR2:
                atomic.StoreUint32(&maint, 0)
            }
        }
    }()
    signal.Notify(ch, syscall.SIGUSR1, syscall.SIGUSR2)
}

Посмотрите промежуточное ПО на это состояние и ответьте соответственно:

func withMaint(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if atomic.LoadUint32(&maint) == 1 {
            http.Error(w, "Down for maintenance", http.StatusServiceUnavailable)
            return
        }
        next.ServeHTTP(w, r)
    })
}

Вы можете применить это промежуточное ПО отдельно для каждого маршрута или напрямую к корневому обработчику сервера :

func main() {
    handleMaintSignals()
    srv := http.Server{
        Addr:    ":17990",
        Handler: withMaint(http.DefaultServeMux),
    }
    srv.ListenAndServe()
}

Вам не нужен второй исполняемый файл, такой как changeMyServerStatus. Используйте инструменты вашей операционной системы для отправки сигналов, такие как pkill :

$ nohup myserver &

$ curl http://localhost:17990/
404 page not found

$ pkill -USR1 myserver

$ curl http://localhost:17990/
Down for maintenance

$ pkill -USR2 myserver

$ curl http://localhost:17990/
404 page not found

Но ручное жонглирование nohup и pkill утомительно и подвержено ошибкам. Вместо этого используйте диспетчер служб, например systemd , для управления процессом. Systemd позволяет отправлять произвольные сигналы с systemctl kill:

systemctl kill -s SIGUSR1 myserver
...