I create a timeout middleware and I keep getting a warning that says ‘Headers were already written. Wanted to override status code 504 with 500‘ whenever it times out. I want to avoid that warning by modifying the timeout to return whatever result the handlers produce, like this:
func Timeout(timeout time.Duration) gin.HandlerFunc {
return func(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), timeout)
defer cancel()
c.Request = c.Request.WithContext(ctx)
resChan := make(chan ResponseData)
go func() {
c.Set(ResChan, resChan)
c.Next()
close(resChan)
}()
select {
case <-resChan:
res := <-resChan
if res.Error != nil && res.Error != context.DeadlineExceeded {
c.JSON(res.StatusCode, response.ErrorResponse(res.Error))
return
} else {
c.JSON(res.StatusCode, response.SuccessResponse(res.Message, res.Data))
}
case <-ctx.Done():
if ctx.Err() == context.DeadlineExceeded {
err := errors.New("Service is unavailable or timed out")
c.JSON(http.StatusGatewayTimeout, response.ErrorResponse(err))
c.Abort()
return
}
}
}
}
However, it appears to be failing to send any data to the resChan channel.
I’ve obtained the channel from the Gin context and I’m using it to send the response, but the channel never receives any data that I send. Where did I go wrong?
func (h *AuthHandler) Register(ctx *gin.Context) {
reqCtx := ctx.Request.Context()
resChan := ctx.MustGet(middleware.ResChan)
var req request.RegisterRequest
if err := ctx.ShouldBind(&req); err != nil {
ctx.JSON(http.StatusBadRequest, response.ErrorResponse(err))
return
}
arg := entity.Admin{
Name: req.Name,
Email: req.Email,
Password: req.Password,
}
result, err := h.authService.Register(reqCtx, arg)
if err != nil {
resChan.(chan middleware.ResponseData) <- middleware.ResponseData{
StatusCode: http.StatusInternalServerError,
Error: err,
}
} else {
resChan.(chan middleware.ResponseData) <- middleware.ResponseData{
StatusCode: http.StatusCreated,
Message: "Registration completed successfully.",
Data: response.NewAdminResponse(result),
}
}
}