Ответить на HTTP-запрос во время обработки в фоновом режиме

#http #go

#http #Вперед

Вопрос:

У меня есть API, который получает CSV-файл для обработки. Я хотел бы иметь возможность отправлять обратно 202 Accepted (или любой статус на самом деле) при обработке файла в фоновом режиме. У меня есть обработчик, который проверяет запрос, записывает заголовок успеха, а затем продолжает обработку с помощью шаблона производитель / потребитель. Проблема в том, что из-за WaitGroup.Wait() вызовов принятый заголовок не отправляется обратно. Ошибки при проверке обработчика отправляются обратно правильно, но это из-за return инструкций.

Возможно ли отправить это 202 Accepted обратно с группами ожидания, как я надеюсь (и если да, то чего мне не хватает)?

 func SomeHandler(w http.ResponseWriter, req *http.Request) {
    endAccepted := time.Now()
    err := verifyRequest(req)
    if err != nil {
        w.WriteHeader(http.StatusBadRequest)
        data := JSONErrors{Errors: []string{err.Error()}}
        json.NewEncoder(w).Encode(data)
        return
    }

    // ...FILE RETRIEVAL CLIPPED (not relevant)...
    // e.g. csvFile, openErr := os.Open(tmpFile.Name())

    //////////////////////////////////////////////////////
    // TODO this isn't sending due to the WaitGroup.Wait()s below
    w.WriteHeader(http.StatusAccepted)
    //////////////////////////////////////////////////////

    // START PRODUCER/CONSUMER
    jobs := make(chan *Job, 100)    // buffered channel
    results := make(chan *Job, 100) // buffered channel

    // start consumers
    for i := 0; i < 5; i   { // 5 consumers
        wg.Add(1)
        go consume(i, jobs, results)
    }
    // start producing
    go produce(jobs, csvFile)

    // start processing
    wg2.Add(1)
    go process(results)

    wg.Wait() // wait for all workers to finish processing jobs

    close(results)

    wg2.Wait() // wait for process to finish

    log.Println("===> Done Processing.")
}
 

Комментарии:

1. 202 : «для HTTP нет возможности позже отправить асинхронный ответ, указывающий результат обработки запроса». Вы не можете отправить обратно окончательный статус. Если это не то, что вы пытаетесь сделать, тогда просто не блокируйте обработчик и дайте ему вернуться.

2. @JimB Да, меня не волнует отправка асинхронного ответа после обработки. Отчет сохраняется. 202 сделано для этого: «[… обрезанный …] указывает, что запрос принят для обработки, но обработка не завершена; фактически, обработка, возможно, еще не началась».

Ответ №1:

Вы выполняете всю обработку в фоновом режиме, но все еще ждете ее завершения. Решением было бы просто не ждать. Лучшим решением было бы перенести всю обработку в другое место в функцию, которую вы можете просто вызвать, go чтобы запустить ее в фоновом режиме, но самым простым решением, оставляющим ее встроенной, было бы просто

 w.WriteHeader(http.StatusAccepted)
go func() {
    // START PRODUCER/CONSUMER
    jobs := make(chan *Job, 100)    // buffered channel
    results := make(chan *Job, 100) // buffered channel

    // start consumers
    for i := 0; i < 5; i   { // 5 consumers
        wg.Add(1)
        go consume(i, jobs, results)
    }
    // start producing
    go produce(jobs, csvFile)

    // start processing
    wg2.Add(1)
    go process(results)

    wg.Wait() // wait for all workers to finish processing jobs

    close(results)

    wg2.Wait() // wait for process to finish

    log.Println("===> Done Processing.")
}()
 

Обратите внимание, что вы исключили обработку файла CSV, поэтому вам нужно убедиться, что этот способ безопасен (т. Е. Вы не defer редактировали закрытие или удаление файла, что привело бы к тому, что это произойдет, как только обработчик вернется).

Комментарии:

1. 🤦 Ого … понедельник … ха-ха. Спасибо @Adrian