Ожидается ли, что в этом случае процедура обработчика Go HTTP будет немедленно завершена? - PullRequest
0 голосов
/ 23 мая 2018

У меня есть один обработчик Go HTTP, подобный этому:

mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
    ctx, cancel := context.WithCancel(context.Background())

    defer cancel()

    if cn, ok := w.(http.CloseNotifier); ok {
        go func(done <-chan struct{}, closed <-chan bool) {
            select {
            case <-done:
            case <-closed:
                fmt.Println("client cancelled....................!!!!!!!!!")
                cancel()
            }
        }(ctx.Done(), cn.CloseNotify())
    }

    time.Sleep(5 * time.Second)

    fmt.Println("I am still running...........")

    fmt.Fprint(w, "cancellation testing......")
})

API работает нормально, затем с помощью curl до завершения запроса я намеренно завершаю команду curl с помощью Control-C, а на стороне сервера -см. client cancelled....................!!!!!!!!! выход из системы, но через некоторое время I am still running........... также выход из системы, я думал, что эта процедура будет немедленно прекращена!

Итак, это желаемое поведение, или я сделал что-то не так?

Если это ожидается, так как независимо от того, что программа завершит свою работу, тогда какой смысл в досрочном аннулировании?

Если я сделал что-то не так, пожалуйста, помогите указать мне правильноеспособ.

1 Ответ

0 голосов
/ 23 мая 2018

Вы создаете contex.Context, который можно отменить, который вы отменяете, когда клиент закрывает соединение, НО вы не проверяете контекст, и ваш обработчик ничего не делает, если он отменяется.Только контекст несет сигналы тайм-аута и отмены, он не имеет ни силы, ни намерения уничтожать / прекращать выполнение программ.Сами goroutines должны отслеживать такие сигналы отмены и действовать в соответствии с ними.

Итак, вы видите ожидаемый вывод вашего кода.

То, что вы хотите, это контролировать контекст, и если этоотменяется, возвращает «немедленно» из обработчика.

Конечно, если вы «спите», вы тем временем не можете контролировать контекст.Поэтому вместо этого используйте time.After(), как в этом примере:

mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    if cn, ok := w.(http.CloseNotifier); ok {
        go func(done <-chan struct{}, closed <-chan bool) {
            select {
            case <-done:
            case <-closed:
                fmt.Println("client cancelled....................!!!!!!!!!")
                cancel()
            }
        }(ctx.Done(), cn.CloseNotify())
    }

    select {
    case <-time.After(5 * time.Second):
        fmt.Println("5 seconds elapsed, client didn't close")
    case <-ctx.Done():
        fmt.Println("Context closed, client closed connection?")
        return
    }

    fmt.Fprint(w, "cancellation testing......")
})
...