Дан сервис. Менять можно только мидлвару throttle: клиент ручки /orders/
обязан получить ответ в пределах таймаута. Если обработчик не успел, клиент
получает ошибку 429 Too Many Requests.
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/orders/", throttle(time.Second, listOrders))
srv := httptest.NewServer(mux)
// ... клиенты в цикле ходят на srv.URL + "/orders?id=N"
}
// Менять можно только эту функцию.
// Ответ по ручке должен приходить в пределах таймаута,
// иначе нужно отдавать ошибку 429.
func throttle(timeout time.Duration, next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
next(w, r)
}
}
func listOrders(w http.ResponseWriter, r *http.Request) {
var order struct {
ID string `json:"id"`
}
order.ID = r.URL.Query().Get("id")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(&order)
}
В исходнике таймаут был зашит в main (1 с). Здесь он параметр throttle,
чтобы его можно было проверить.
Требования
next успел за timeout → клиент получает ровно его ответ: код
(по умолчанию 200), заголовки, тело.
next не успел → клиент получает 429 не позже чем через timeout
(плюс накладные расходы), даже если next игнорирует контекст и
работает ещё долго. Всё, что next запишет после этого (код, заголовки, тело),
до клиента не доходит и не вызывает гонок.
next получает запрос, контекст которого отменяется по таймауту, чтобы он
мог бросить работу.
- Запросы обрабатываются независимо и параллельно.
- Когда
next завершился, от мидлвары не остаётся горутин.
Код проходит go test -race.
Пример
h := throttle(100*time.Millisecond, slowHandler) // slowHandler спит 1 с
// GET → через ~100 мс 429; через 1 с slowHandler пишет 200 «в пустоту»
Устно: почему нельзя просто запустить next(w, r) в горутине и по таймауту
написать в тот же w код 429? Чем 429 отличается от 503/504 и какой код
правильнее здесь? Что делать, если next паникует?
Разбор и эталонное решение — после своей попытки: на собеседовании подсказок не будет.
Сначала попробуй сам — подсказки не дают готовый ответ.