From 0d9996e77df1c44718b9d1fd6d80946f6893fb70 Mon Sep 17 00:00:00 2001 From: Artem Poltorzhitskiy Date: Tue, 28 May 2024 19:58:04 +0200 Subject: [PATCH] Try to fix cancellation error (#202) * Try to fix cancellation error * Fix: timeout middleware * 502 on cancel request --- cmd/api/handler/block.go | 2 +- cmd/api/handler/error.go | 13 ++++++++++--- cmd/api/handler/namespace.go | 2 +- cmd/api/handler/search.go | 2 +- cmd/api/handler/state.go | 2 +- cmd/api/handler/stats.go | 20 ++++++++++---------- cmd/api/init.go | 21 ++++++++++++--------- 7 files changed, 36 insertions(+), 26 deletions(-) diff --git a/cmd/api/handler/block.go b/cmd/api/handler/block.go index 5cbd268e..93cb7845 100644 --- a/cmd/api/handler/block.go +++ b/cmd/api/handler/block.go @@ -193,7 +193,7 @@ func (handler *BlockHandler) GetEvents(c echo.Context) error { if handler.block.IsNoRows(err) { return returnArray(c, []any{}) } - return internalServerError(c, err) + return handleError(c, err, handler.block) } fltrs := storage.EventFilter{ diff --git a/cmd/api/handler/error.go b/cmd/api/handler/error.go index 5d962f86..a769e266 100644 --- a/cmd/api/handler/error.go +++ b/cmd/api/handler/error.go @@ -15,6 +15,7 @@ import ( var ( errInvalidHashLength = errors.New("invalid hash: should be 32 bytes length") errInvalidAddress = errors.New("invalid address") + errCancelRequest = "pq: canceling statement due to user request" ) type NoRows interface { @@ -33,9 +34,7 @@ func badRequestError(c echo.Context, err error) error { func internalServerError(c echo.Context, err error) error { if hub := sentryecho.GetHubFromContext(c); hub != nil { - if !errors.Is(err, context.Canceled) { - hub.CaptureMessage(err.Error()) - } + hub.CaptureMessage(err.Error()) } return c.JSON(http.StatusInternalServerError, Error{ Message: err.Error(), @@ -46,6 +45,14 @@ func handleError(c echo.Context, err error, noRows NoRows) error { if err == nil { return nil } + if err.Error() == errCancelRequest { + return nil + } + if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { + return c.JSON(http.StatusBadGateway, Error{ + Message: err.Error(), + }) + } if noRows.IsNoRows(err) { return c.NoContent(http.StatusNoContent) } diff --git a/cmd/api/handler/namespace.go b/cmd/api/handler/namespace.go index 683f69f6..4149352c 100644 --- a/cmd/api/handler/namespace.go +++ b/cmd/api/handler/namespace.go @@ -375,7 +375,7 @@ func (handler *NamespaceHandler) Blob(c echo.Context) error { response, err := responses.NewBlob(blob) if err != nil { - return internalServerError(c, err) + return handleError(c, err, handler.blobLogs) } return c.JSON(http.StatusOK, response) diff --git a/cmd/api/handler/search.go b/cmd/api/handler/search.go index 8b7125dc..9a59320b 100644 --- a/cmd/api/handler/search.go +++ b/cmd/api/handler/search.go @@ -106,7 +106,7 @@ func (handler SearchHandler) Search(c echo.Context) error { } if err != nil { if !handler.address.IsNoRows(err) { - return internalServerError(c, err) + return handleError(c, err, handler.address) } } diff --git a/cmd/api/handler/state.go b/cmd/api/handler/state.go index 413e979d..ea2cd966 100644 --- a/cmd/api/handler/state.go +++ b/cmd/api/handler/state.go @@ -45,7 +45,7 @@ func (sh *StateHandler) Head(c echo.Context) error { votingPower, err := sh.validator.TotalVotingPower(c.Request().Context()) if err != nil { - return internalServerError(c, err) + return handleError(c, err, sh.state) } state.TotalVotingPower = votingPower diff --git a/cmd/api/handler/stats.go b/cmd/api/handler/stats.go index db7e9558..4c7e69e9 100644 --- a/cmd/api/handler/stats.go +++ b/cmd/api/handler/stats.go @@ -82,7 +82,7 @@ func (sh StatsHandler) Summary(c echo.Context) error { if errors.Is(err, storage.ErrValidation) { return badRequestError(c, err) } - return internalServerError(c, err) + return handleError(c, err, sh.nsRepo) } return c.JSON(http.StatusOK, summary) @@ -144,7 +144,7 @@ func (sh StatsHandler) Histogram(c echo.Context) error { }) } if err != nil { - return internalServerError(c, err) + return handleError(c, err, sh.nsRepo) } response := make([]responses.HistogramItem, len(histogram)) @@ -168,7 +168,7 @@ func (sh StatsHandler) Histogram(c echo.Context) error { func (sh StatsHandler) TPS(c echo.Context) error { tps, err := sh.repo.TPS(c.Request().Context()) if err != nil { - return internalServerError(c, err) + return handleError(c, err, sh.nsRepo) } return c.JSON(http.StatusOK, responses.NewTPS(tps)) } @@ -186,7 +186,7 @@ func (sh StatsHandler) TPS(c echo.Context) error { func (sh StatsHandler) TxCountHourly24h(c echo.Context) error { histogram, err := sh.repo.TxCountForLast24h(c.Request().Context()) if err != nil { - return internalServerError(c, err) + return handleError(c, err, sh.nsRepo) } response := make([]responses.TxCountHistogramItem, len(histogram)) for i := range histogram { @@ -222,7 +222,7 @@ func (sh StatsHandler) NamespaceUsage(c echo.Context) error { namespaces, err := sh.nsRepo.ListWithSort(c.Request().Context(), "size", sdk.SortOrderDesc, *req.Top, 0) if err != nil { - return internalServerError(c, err) + return handleError(c, err, sh.nsRepo) } var top100Size int64 @@ -234,7 +234,7 @@ func (sh StatsHandler) NamespaceUsage(c echo.Context) error { state, err := sh.state.List(c.Request().Context(), 1, 0, sdk.SortOrderAsc) if err != nil { - return internalServerError(c, err) + return handleError(c, err, sh.nsRepo) } if len(state) == 0 { return returnArray(c, response) @@ -284,7 +284,7 @@ func (sh StatsHandler) Series(c echo.Context) error { storage.NewSeriesRequest(req.From, req.To), ) if err != nil { - return internalServerError(c, err) + return handleError(c, err, sh.nsRepo) } response := make([]responses.SeriesItem, len(histogram)) @@ -345,7 +345,7 @@ func (sh StatsHandler) NamespaceSeries(c echo.Context) error { storage.NewSeriesRequest(req.From, req.To), ) if err != nil { - return internalServerError(c, err) + return handleError(c, err, sh.nsRepo) } response := make([]responses.SeriesItem, len(histogram)) @@ -419,7 +419,7 @@ func (sh StatsHandler) PriceSeries(c echo.Context) error { func (sh StatsHandler) PriceCurrent(c echo.Context) error { price, err := sh.price.Last(c.Request().Context()) if err != nil { - return internalServerError(c, err) + return handleError(c, err, sh.nsRepo) } return c.JSON(http.StatusOK, responses.NewPrice(price)) @@ -463,7 +463,7 @@ func (sh StatsHandler) StakingSeries(c echo.Context) error { storage.NewSeriesRequest(req.From, req.To), ) if err != nil { - return internalServerError(c, err) + return handleError(c, err, sh.nsRepo) } response := make([]responses.SeriesItem, len(histogram)) diff --git a/cmd/api/init.go b/cmd/api/init.go index 3930e2c9..e333eb34 100644 --- a/cmd/api/init.go +++ b/cmd/api/init.go @@ -143,6 +143,7 @@ func cacheSkipper(c echo.Context) bool { func initEcho(cfg ApiConfig, db postgres.Storage, env string) *echo.Echo { e := echo.New() e.Validator = handler.NewCelestiaApiValidator() + e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{ LogURI: true, LogStatus: true, @@ -183,6 +184,17 @@ func initEcho(cfg ApiConfig, db postgres.Storage, env string) *echo.Echo { return nil }, })) + + timeout := 30 * time.Second + if cfg.RequestTimeout > 0 { + timeout = time.Duration(cfg.RequestTimeout) * time.Second + } + e.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{ + Skipper: websocketSkipper, + Timeout: timeout, + ErrorMessage: `{"message":"timeout"}`, + })) + e.Use(middleware.GzipWithConfig(middleware.GzipConfig{ Skipper: gzipSkipper, })) @@ -201,15 +213,6 @@ func initEcho(cfg ApiConfig, db postgres.Storage, env string) *echo.Echo { e.Use(middleware.Secure()) e.Pre(middleware.RemoveTrailingSlash()) - timeout := 30 * time.Second - if cfg.RequestTimeout > 0 { - timeout = time.Duration(cfg.RequestTimeout) * time.Second - } - e.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{ - Skipper: websocketSkipper, - Timeout: timeout, - })) - if cfg.Prometheus { e.Use(echoprometheus.NewMiddlewareWithConfig(echoprometheus.MiddlewareConfig{ Namespace: "celestia_api",