본문 바로가기
golang

[TIL] golang http server에 timeout handler 추가하기

by marble25 2023. 12. 25.

Golang 서버에 timeout을 적용할 방법을 찾다가 나온 내용을 정리해둔다.

방법 1: http server에 timeout 설정

server := &http.Server{
	Handler: h,
	ReadTimeout: 3 * time.Minute,
	WriteTimeout: 3 * time.Minute,
}
  • ReadTimeout: body를 포함한 전체 request를 읽기 위한 timeout. Handler가 request body의 허용 가능한 deadline이나 upload rate에 대한 request 별 decision을 내리지 않기 때문에 ReadHeaderTimeout을 사용하는 것이 권고된다.
  • ReadHeaderTimeout: header를 읽는데 허용된 시간. Header를 다 읽으면 초기화되고, handler는 body가 느리다고 여겨지는 정도를 결정할 수 있다.
  • WriteTimeout: 응답을 보내기 위해 허용되는 최대 시간. Handler가 request별로 결정을 내리도록 하지는 않는다.
  • IdleTimeout: Keep-alive option이 enable되어 있을 때 다음 request까지 기다릴 수 있는 시간.
  • MaxHeaderBytes: Header의 max bytes. Body는 포함되지 않는다.

하지만 이 방식으로 timeout을 설정할 경우 아무런 오류 메세지 없이 connection이 끊길 수 있다.

$ curl -v localhost:8080/api/health
*   Trying [::1]:8080...
* connect to ::1 port 8080 failed: Connection refused
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080
> GET /api/health HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.4.0
> Accept: */*
>
* Empty reply from server
* Closing connection
curl: (52) Empty reply from server

아무런 에러코드 없이 실패하기 때문에 production에서 사용하기 어렵다.

방법 2: http server에 timeout handler 설정

server := &http.Server{
	Handler:      http.TimeoutHandler(router, 3*time.Minute, "Request timeout: 180 seconds"), // 3분 timeout
	ReadTimeout:  4 * time.Minute,
	WriteTimeout: 4 * time.Minute,
}

다음과 같이 timeout handler로 handler를 감쌀 수 있다.

Timeout handler는 미들웨어로 구성되어 이후 handler에 대해서는 기존과 동일하게 동작함을 보장받을 수 있다.

$ curl -v localhost:8080/api/health
*   Trying [::1]:8080...
* connect to ::1 port 8080 failed: Connection refused
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080
> GET /api/health HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.4.0
> Accept: */*
>
< HTTP/1.1 503 Service Unavailable
< Date: Mon, 25 Dec 2023 07:58:48 GMT
< Content-Length: 28
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host localhost left intact
Request timeout: 180 seconds

3분의 timeout이 지난 후 다음과 같이 503 response가 온다.

에러 코드도 있고, 에러 메세지도 오기 때문에 좀 더 안전하게 실패할 수 있다. 방법 1과 방법 2를 혼합해서 사용해보면 좋을 것 같다.

'golang' 카테고리의 다른 글

[TIL] golang promauto metric register시 panic  (0) 2023.12.21
[TIL] golang buffer 복사  (1) 2023.12.21
Go google style guides - decisions  (0) 2023.12.09
Go google style guide - overview & guide  (1) 2023.11.19
Go garbage collection  (1) 2023.10.30