golang выполнить функцию после http.ListenAndServe

Я начинаю изучать golang, создавая простой http-сервер.

func main() {
    f, err := os.OpenFile("testlogfile", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
    if err != nil {
        fmt.Println("error opening file: %v", err)
    }
    defer f.Close()

    log.SetOutput(f)

    http.HandleFunc("/", defaultHandler)
    http.HandleFunc("/check", checkHandler)

    serverErr := http.ListenAndServe("127.0.0.1:8080", nil) // set listen port

    if serverErr != nil {
        log.Println("Error starting server")

    } else {
        fmt.Println("Started server on - 127.0.0.1:8080" )
    }
}

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

Однако теперь я хочу запустить отдельную процедуру go, которая просматривает файл -

func initWatch() string{
    watcher, err := fsnotify.NewWatcher()
    if err != nil {
        fmt.Println(err)
    }
    defer watcher.Close()

    done := make(chan bool)
    go func() {
        for {
            select {
                case event := <-watcher.Events:
                    if ( event.Op&fsnotify.Remove == fsnotify.Remove || event.Op&fsnotify.Rename == fsnotify.Rename ) {
                        fmt.Println("file removed - ", event.Name)
                    }

                case err := <-watcher.Errors:
                    fmt.Println("error:", err)
                }
        }
    }()

    err = watcher.Add("sampledata.txt")
    if err != nil {
        fmt.Println(err)
    }


    <-done
}

И теперь, если я вызову функцию initWatch() ДО http.ListenAndServe("127.0.0.1:8080", nil), я не смогу получить доступ к маршрутам сервера через браузер (например, localhost:8080), потому что сервер не создан. Бывший -

initWatch()
serverErr := http.ListenAndServe("127.0.0.1:8080", nil) // set listen port

И если я вызову функцию initWatch() ПОСЛЕ http.ListenAndServe("127.0.0.1:8080", nil), то функция просмотра файлов не работает. Бывший -

serverErr := http.ListenAndServe("127.0.0.1:8080", nil) // set listen port
initWatch()

Как мне заставить работать и initWatch() (наблюдатель за файлами), и http-сервер?

Ценю вашу помощь.


person Ajey    schedule 16.10.2017    source источник
comment
Возможно, объясните, что именно initWatch() хочет делать с маршрутами? Там нет кода для доступа к localhost:8080. Вы можете настроить маршрутизатор отдельно от сервера, см. документацию для ListenAndServe. Какую ошибку/проблему вы видите, если ставили раньше?   -  person Kenny Grant    schedule 16.10.2017


Ответы (2)


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

done := initWatch()
serverErr := http.ListenAndServe("127.0.0.1:8080", nil)
done <- true

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

func initWatch() chan bool {
    watcher, err := fsnotify.NewWatcher()
    if err != nil {
        fmt.Println(err)
    }
    defer watcher.Close()

    done := make(chan bool)
    go func() {
        for {
            select {
                case event := <-watcher.Events:
                    if ( event.Op&fsnotify.Remove == fsnotify.Remove || event.Op&fsnotify.Rename == fsnotify.Rename ) {
                        fmt.Println("file removed - ", event.Name)
                    }

                case err := <-watcher.Errors:
                    fmt.Println("error:", err)

                // listen exit signal
                case <- done:
                     break
            }
        }
    }()




    err = watcher.Add("sampledata.txt")
    if err != nil {
        fmt.Println(err)
    }
    return done
}
person Eugene Lisitsky    schedule 17.10.2017

Оба вызова, initWatch() и http.ListenAndServe("127.0.0.1:8080", nil), заставляют основную горутину ждать вечно. initWatch() ожидает значение в операторе <-done и никогда его не получает. Вы должны запустить initWatch или http.ListenAndServe в другой горутине, например, go initWatch(). Или, может быть, отправить значение в канал done из другой горутины.

person lamg    schedule 16.10.2017