Open robert-min opened 1 year ago
func handlePing(w http.ResponseWriter, r *http.Request) {
log.Println("ping: Got a request")
time.Sleep(3 * time.Second)
fmt.Fprintf(w, "pong")
}
func doSomeWork(data []byte) {
time.Sleep(5 * time.Second)
}
func handleUserAPI(w http.ResponseWriter, r *http.Request) {
done := make(chan bool)
log.Println("I started processing the request")
req, err := http.NewRequestWithContext(
r.Context(),
"GET",
"http://localhost:8080/ping", nil,
)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
client := &http.Client{}
log.Println("Outgoing HTTP request")
resp, err := client.Do(req)
if err != nil {
log.Printf("Error making request: %v\n", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
log.Println("Processing the response i got")
go func() {
doSomeWork(data)
done <- true
}()
select {
case <-done:
log.Println("doSomeWork done: Continuing request processing")
case <-r.Context().Done():
log.Printf("Aborting request processing: %v\n", r.Context().Err())
return
}
fmt.Fprintf(w, string(data))
log.Println("I finished procesing the request")
}
func main() {
listenAddr := os.Getenv("LISTEN_ADDR")
if len(listenAddr) == 0 {
listenAddr = ":8080"
}
timeoutDuration := 30 * time.Second
userHandler := http.HandlerFunc(handleUserAPI)
hTimeout := http.TimeoutHandler(
userHandler,
timeoutDuration,
"I ran out of time",
)
mux := http.NewServeMux()
mux.Handle("/api/users", hTimeout)
mux.HandleFunc("/ping", handlePing)
log.Fatal(http.ListenAndServe(":8080", mux))
}
http.Server
구조체를 수정하여 서버의 모든 핸들러에 공통 타임아웃 수정
func handleUserAPi(w http.ResponseWriter, r *http.Request) {
log.Println("I started processing the request")
defer r.Body.Close()
data, err := io.ReadAll(r.Body)
if err != nil {
log.Printf("Error reading body %v\n", err)
http.Error(
w, "Error reading body", http.StatusInternalServerError,
)
return
}
log.Println(string(data))
fmt.Fprintf(w, "Hello world!")
log.Println("I finsiehd processing")
}
func main() {
listenAddr := os.Getenv("LISTEN_ADDR")
if len(listenAddr) == 0 {
listenAddr = ":8080"
}
mux := http.NewServeMux()
mux.HandleFunc("/api/users", handleUserAPi)
s := http.Server{
Addr: listenAddr,
Handler: mux,
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
}
log.Fatal(s.ListenAndServe())
}
http.Server
객체에 정의된 Shutdown 매서드를 활용해 구현
func handleUserAPI(w http.ResponseWriter, r *http.Request) {
log.Println("I started processing the request")
defer r.Body.Close()
data, err := io.ReadAll(r.Body)
if err != nil {
log.Printf("Error reading body: %v\n", err)
http.Error(
w, "Error reading body",
http.StatusInternalServerError,
)
return
}
log.Println(string(data))
fmt.Fprintf(w, "Hello world!")
log.Println("I finished processing the request")
}
func shutDown(ctx context.Context, s *http.Server, waitForShutdownCompletion chan struct{}) {
sigch := make(chan os.Signal, 1)
signal.Notify(sigch, syscall.SIGINT, syscall.SIGTERM)
sig := <-sigch
log.Printf("Got signal: %v . Server shutting down.", sig)
// shutdown 매서드가 현재 서버 상에 존재하는 요청을 처리하는 동안 최대로 기다릴 시간
childCtx, cancel := context.WithTimeout(
ctx, 30*time.Second,
)
defer cancel()
if err := s.Shutdown(childCtx); err != nil {
log.Printf("Error during shutdown: %v", err)
}
waitForShutdownCompletion <- struct{}{}
}
func main() {
listenAddr := os.Getenv("LISTEN_ADDR")
if len(listenAddr) == 0 {
listenAddr = ":8080"
}
mux := http.NewServeMux()
mux.HandleFunc("/api/users", handleUserAPI)
s := http.Server{
Addr: listenAddr,
Handler: mux,
}
waitForShutdownCompletion := make(chan struct{})
go shutDown(context.Background(), &s, waitForShutdownCompletion)
err := s.ListenAndServe()
log.Print(
"Wainting for shutdown to complete...",
)
<-waitForShutdownCompletion
log.Fatal(err)
}
클라이언트 연결 끊김 처리