From 39c6fd92bfe1acd225dda31c3b81d80495fcf954 Mon Sep 17 00:00:00 2001 From: Lucas Lemos Date: Thu, 29 Feb 2024 04:50:13 -0300 Subject: [PATCH] :recycle: refactor: Migrate HealthChecker to v3 (#2884) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update pull_request_template.md * Update v3-changes.md * Update CONTRIBUTING.md (#2752) Grammar correction. * chore(encryptcookie)!: update default config (#2753) * chore(encryptcookie)!: update default config docs(encryptcookie): enhance documentation and examples BREAKING CHANGE: removed the hardcoded "csrf_" from the Except. * docs(encryptcookie): reads or modifies cookies * chore(encryptcookie): csrf config example * docs(encryptcookie): md table spacing * build(deps): bump actions/setup-go from 4 to 5 (#2754) Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4 to 5. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-go dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * 🩹 middleware/logger/: log client IP address by default (#2755) * middleware/logger: Log client IP address by default. * Update doc. * fix: don't constrain middlewares' context-keys to strings :bug: (#2751) * Revert "Revert ":bug: requestid.Config.ContextKey is interface{} (#2369)" (#2742)" This reverts commit 28be17f929cfa7d3c27dd292fc3956f2f9882e22. * fix: request ContextKey default value condition Should check for `nil` since it is `any`. * fix: don't constrain middlewares' context-keys to strings `context` recommends using "unexported type" as context keys to avoid collisions https://pkg.go.dev/github.com/gofiber/fiber/v2#Ctx.Locals. The official go blog also recommends this https://go.dev/blog/context. `fiber.Ctx.Locals(key any, value any)` correctly allows consumers to use unexported types or e.g. strings. But some fiber middlewares constrain their context-keys to `string` in their "default config structs", making it impossible to use unexported types. This PR removes the `string` _constraint_ from all middlewares, allowing to now use unexported types as per the official guidelines. However the default value is still a string, so it's not a breaking change, and anyone still using strings as context keys is not affected. * 📚 Update app.md for indentation (#2761) Update app.md for indentation * build(deps): bump github.com/google/uuid from 1.4.0 to 1.5.0 (#2762) Bumps [github.com/google/uuid](https://github.com/google/uuid) from 1.4.0 to 1.5.0. - [Release notes](https://github.com/google/uuid/releases) - [Changelog](https://github.com/google/uuid/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) --- updated-dependencies: - dependency-name: github.com/google/uuid dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github/codeql-action from 2 to 3 (#2763) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v2...v3) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Changing default log output (#2730) changing default log output Closes #2729 * Update hooks.md fix wrong hooks signature * 🩹 Fix: CORS middleware should use the defined AllowedOriginsFunc config when AllowedOrigins is empty (#2771) * 🐛 [Bug]: Adaptator + otelfiber issue #2641 (#2772) * 🩹🚨 - fix for redirect with query params (#2748) * redirect with query params did not work, fix it and add test for it * redirect middleware - fix test typo * ♻️ logger/middleware colorize logger error message #2593 (#2773) * :sparkles: feat: add liveness and readiness checks (#2509) * :sparkles: feat: add liveness and readiness checkers * :memo: docs: add docs for liveness and readiness * :sparkles: feat: add options method for probe checkers * :white_check_mark: tests: add tests for liveness and readiness * :recycle: refactor: change default endpoint values * :recycle: refactor: change default value for liveness endpoint * :memo: docs: add return status for liveness and readiness probes * :recycle: refactor: change probechecker to middleware * :memo: docs: move docs to middleware session * :recycle: refactor: apply gofumpt formatting * :recycle: refactor: remove unused parameter * split config and apply a review * apply reviews and add testcases * add benchmark * cleanup * rename middleware * fix linter * Update docs and config values * Revert change to IsReady * Updates based on code review * Update docs to match other middlewares --------- Co-authored-by: Muhammed Efe Cetin Co-authored-by: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Co-authored-by: Juan Calderon-Perez * prepare release v2.52.0 - add more Parser tests * fix healthcheck.md * configure workflows for V2 branch * configure workflows for V2 branch * Fix default value to false in docs of QueryBool (#2811) fix default value to false in docs of QueryBool * update queryParser config * Update ctx.md * Update routing.md * merge v2 in v3 * merge v2 in v3 * lint fixes * :books: Doc: Fix code snippet indentation in /docs/api/middleware/keyauth.md Removes an an extra level of indentation in line 51 of `keyauth.md` [here](https://github.com/gofiber/fiber/blob/v2/docs/api/middleware/keyauth.md?plain=1#L51) * fix: healthcheck middleware not working with route group (#2863) * fix: healthcheck middleware not working with route group * perf: change verification method to improve perf * Update healthcheck_test.go * test: add not matching route test for strict routing * add more test cases * correct tests * correct test helpers * correct tests * correct tests --------- Co-authored-by: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Co-authored-by: René Werner * merge v2 in v3 * Merge pull request from GHSA-fmg4-x8pw-hjhg * Enforce Wildcard Origins with AllowCredentials check * Expand unit-tests, fix issues with subdomains logic, update docs * Update cors.md * Added test using localhost, ipv4, and ipv6 address * improve documentation markdown --------- Co-authored-by: René Werner * Update app.go prepare release v2.52.1 * fix cors domain normalize * fix sync-docs workflow * test: fix failing tests * fix sync-docs workflow * test: cors middleware use testify require * chore: fix lint warnings * chore: revert test isolation. * feat: migrate healthchecker to v3 * fix: use Get instead of Use for better router matching * docs: update docs to v3 info * fixed the fasthttp ctx race condition problem * Update middleware/cors/utils.go Co-authored-by: Renan Bastos * fix sync_docs.sh * fix review comments/hints * fix review comments/hints * stabilize Test_Proxy_Timeout_Slow_Server test * stabilize Test_Proxy_.* tests * ignore bodyclose linter for tests use http.NoBody instead of nil * Add parallel benchmark * Update healthcheck_test.go * docs: add comments for next behavior when there are no other handlers defined * revert(tests): undo http.NoBody usage --------- Signed-off-by: dependabot[bot] Co-authored-by: RW Co-authored-by: tokelo-12 <113810058+tokelo-12@users.noreply.github.com> Co-authored-by: Jason McNeil Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: iRedMail <2048991+iredmail@users.noreply.github.com> Co-authored-by: Benjamin Grosse Co-authored-by: Mehmet Firat KOMURCU Co-authored-by: Bruno Co-authored-by: Muhammad Kholid B Co-authored-by: gilwo Co-authored-by: Muhammed Efe Cetin Co-authored-by: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Co-authored-by: Juan Calderon-Perez Co-authored-by: Jongmin Kim Co-authored-by: Giovanni Rivera Co-authored-by: Renan Bastos --- docs/api/middleware/healthcheck.md | 67 +++++------ middleware/healthcheck/config.go | 61 ++-------- middleware/healthcheck/healthcheck.go | 43 +------ middleware/healthcheck/healthcheck_test.go | 126 ++++++++------------- 4 files changed, 97 insertions(+), 200 deletions(-) diff --git a/docs/api/middleware/healthcheck.md b/docs/api/middleware/healthcheck.md index 666d51ef12f..4c246046a1e 100644 --- a/docs/api/middleware/healthcheck.md +++ b/docs/api/middleware/healthcheck.md @@ -39,19 +39,39 @@ import ( After you initiate your [Fiber](https://github.com/gofiber/fiber) app, you can use the following possibilities: ```go -// Provide a minimal config -app.Use(healthcheck.New()) +// Provide a minimal config for liveness check +app.Get(healthcheck.DefaultLivenessEndpoint, healthcheck.New()) +// Provide a minimal config for readiness check +app.Get(healthcheck.DefaultReadinessEndpoint, healthcheck.New()) +// Provide a minimal config for check with custom endpoint +app.Get("/live", healthcheck.New()) // Or extend your config for customization -app.Use(healthcheck.New(healthcheck.Config{ - LivenessProbe: func(c fiber.Ctx) bool { +app.Get(healthcheck.DefaultLivenessEndpoint, healthcheck.New(healthcheck.Config{ + Probe: func(c fiber.Ctx) bool { return true }, - LivenessEndpoint: "/live", - ReadinessProbe: func(c fiber.Ctx) bool { - return serviceA.Ready() && serviceB.Ready() && ... +})) +// And it works the same for readiness, just change the route +app.Get(healthcheck.DefaultReadinessEndpoint, healthcheck.New(healthcheck.Config{ + Probe: func(c fiber.Ctx) bool { + return true + }, +})) +// With a custom route and custom probe +app.Get("/live", healthcheck.New(healthcheck.Config{ + Probe: func(c fiber.Ctx) bool { + return true + }, +})) + +// It can also be used with app.All, although it will only respond to requests with the GET method +// in case of calling the route with any method which isn't GET, the return will be 404 Not Found when app.All is used +// and 405 Method Not Allowed when app.Get is used +app.All(healthcheck.DefaultReadinessEndpoint, healthcheck.New(healthcheck.Config{ + Probe: func(c fiber.Ctx) bool { + return true }, - ReadinessEndpoint: "/ready", })) ``` @@ -59,7 +79,9 @@ app.Use(healthcheck.New(healthcheck.Config{ ```go type Config struct { - // Next defines a function to skip this middleware when returned true. + // Next defines a function to skip this middleware when returned true. If this function returns true + // and no other handlers are defined for the route, Fiber will return a status 404 Not Found, since + // no other handlers were defined to return a different status. // // Optional. Default: nil Next func(fiber.Ctx) bool @@ -69,23 +91,7 @@ type Config struct { // the application is in a state where it can handle requests (e.g., the server is up and running). // // Optional. Default: func(c fiber.Ctx) bool { return true } - LivenessProbe HealthChecker - - // HTTP endpoint at which the liveness probe will be available. - // - // Optional. Default: "/livez" - LivenessEndpoint string - - // Function used for checking the readiness of the application. Returns true if the application - // is ready to process requests and false otherwise. The readiness probe typically checks if all necessary - // services, databases, and other dependencies are available for the application to function correctly. - // - // Optional. Default: func(c fiber.Ctx) bool { return true } - ReadinessProbe HealthChecker - - // HTTP endpoint at which the readiness probe will be available. - // Optional. Default: "/readyz" - ReadinessEndpoint string + Probe HealthChecker } ``` @@ -93,14 +99,9 @@ type Config struct { The default configuration used by this middleware is defined as follows: ```go -func defaultLivenessProbe(fiber.Ctx) bool { return true } - -func defaultReadinessProbe(fiber.Ctx) bool { return true } +func defaultProbe(fiber.Ctx) bool { return true } var ConfigDefault = Config{ - LivenessProbe: defaultLivenessProbe, - ReadinessProbe: defaultReadinessProbe, - LivenessEndpoint: "/livez", - ReadinessEndpoint: "/readyz", + Probe: defaultProbe, } ``` diff --git a/middleware/healthcheck/config.go b/middleware/healthcheck/config.go index 59916fc8698..8b7b26a267a 100644 --- a/middleware/healthcheck/config.go +++ b/middleware/healthcheck/config.go @@ -6,7 +6,9 @@ import ( // Config defines the configuration options for the healthcheck middleware. type Config struct { - // Next defines a function to skip this middleware when returned true. + // Next defines a function to skip this middleware when returned true. If this function returns true + // and no other handlers are defined for the route, Fiber will return a status 404 Not Found, since + // no other handlers were defined to return a different status. // // Optional. Default: nil Next func(fiber.Ctx) bool @@ -16,23 +18,7 @@ type Config struct { // the application is in a state where it can handle requests (e.g., the server is up and running). // // Optional. Default: func(c fiber.Ctx) bool { return true } - LivenessProbe HealthChecker - - // HTTP endpoint at which the liveness probe will be available. - // - // Optional. Default: "/livez" - LivenessEndpoint string - - // Function used for checking the readiness of the application. Returns true if the application - // is ready to process requests and false otherwise. The readiness probe typically checks if all necessary - // services, databases, and other dependencies are available for the application to function correctly. - // - // Optional. Default: func(c fiber.Ctx) bool { return true } - ReadinessProbe HealthChecker - - // HTTP endpoint at which the readiness probe will be available. - // Optional. Default: "/readyz" - ReadinessEndpoint string + Probe HealthChecker } const ( @@ -40,44 +26,19 @@ const ( DefaultReadinessEndpoint = "/readyz" ) -func defaultLivenessProbe(fiber.Ctx) bool { return true } - -func defaultReadinessProbe(fiber.Ctx) bool { return true } - -// ConfigDefault is the default config -var ConfigDefault = Config{ - LivenessProbe: defaultLivenessProbe, - ReadinessProbe: defaultReadinessProbe, - LivenessEndpoint: DefaultLivenessEndpoint, - ReadinessEndpoint: DefaultReadinessEndpoint, -} +func defaultProbe(fiber.Ctx) bool { return true } -// defaultConfig returns a default config for the healthcheck middleware. -func defaultConfig(config ...Config) Config { +func defaultConfigV3(config ...Config) Config { if len(config) < 1 { - return ConfigDefault + return Config{ + Probe: defaultProbe, + } } cfg := config[0] - if cfg.Next == nil { - cfg.Next = ConfigDefault.Next - } - - if cfg.LivenessProbe == nil { - cfg.LivenessProbe = defaultLivenessProbe - } - - if cfg.ReadinessProbe == nil { - cfg.ReadinessProbe = defaultReadinessProbe - } - - if cfg.LivenessEndpoint == "" { - cfg.LivenessEndpoint = DefaultLivenessEndpoint - } - - if cfg.ReadinessEndpoint == "" { - cfg.ReadinessEndpoint = DefaultReadinessEndpoint + if cfg.Probe == nil { + cfg.Probe = defaultProbe } return cfg diff --git a/middleware/healthcheck/healthcheck.go b/middleware/healthcheck/healthcheck.go index 222b6f44524..51a16d70d3a 100644 --- a/middleware/healthcheck/healthcheck.go +++ b/middleware/healthcheck/healthcheck.go @@ -1,36 +1,14 @@ package healthcheck import ( - "strings" - "github.com/gofiber/fiber/v3" ) // HealthChecker defines a function to check liveness or readiness of the application type HealthChecker func(fiber.Ctx) bool -// HealthCheckerHandler defines a function that returns a HealthChecker -type HealthCheckerHandler func(HealthChecker) fiber.Handler - -func healthCheckerHandler(checker HealthChecker) fiber.Handler { - return func(c fiber.Ctx) error { - if checker == nil { - return c.Next() - } - - if checker(c) { - return c.SendStatus(fiber.StatusOK) - } - - return c.SendStatus(fiber.StatusServiceUnavailable) - } -} - -func New(config ...Config) fiber.Handler { - cfg := defaultConfig(config...) - - isLiveHandler := healthCheckerHandler(cfg.LivenessProbe) - isReadyHandler := healthCheckerHandler(cfg.ReadinessProbe) +func NewHealthChecker(config ...Config) fiber.Handler { + cfg := defaultConfigV3(config...) return func(c fiber.Ctx) error { // Don't execute middleware if Next returns true @@ -42,21 +20,10 @@ func New(config ...Config) fiber.Handler { return c.Next() } - prefixCount := len(strings.TrimRight(c.Route().Path, "/")) - if len(c.Path()) >= prefixCount { - checkPath := c.Path()[prefixCount:] - checkPathTrimmed := checkPath - if !c.App().Config().StrictRouting { - checkPathTrimmed = strings.TrimRight(checkPath, "/") - } - switch { - case checkPath == cfg.ReadinessEndpoint || checkPathTrimmed == cfg.ReadinessEndpoint: - return isReadyHandler(c) - case checkPath == cfg.LivenessEndpoint || checkPathTrimmed == cfg.LivenessEndpoint: - return isLiveHandler(c) - } + if cfg.Probe(c) { + return c.SendStatus(fiber.StatusOK) } - return c.Next() + return c.SendStatus(fiber.StatusServiceUnavailable) } } diff --git a/middleware/healthcheck/healthcheck_test.go b/middleware/healthcheck/healthcheck_test.go index 409b985a60b..e6c17487295 100644 --- a/middleware/healthcheck/healthcheck_test.go +++ b/middleware/healthcheck/healthcheck_test.go @@ -34,7 +34,8 @@ func Test_HealthCheck_Strict_Routing_Default(t *testing.T) { StrictRouting: true, }) - app.Use(New()) + app.Get("/livez", NewHealthChecker()) + app.Get("/readyz", NewHealthChecker()) shouldGiveOK(t, app, "/readyz") shouldGiveOK(t, app, "/livez") @@ -44,71 +45,12 @@ func Test_HealthCheck_Strict_Routing_Default(t *testing.T) { shouldGiveNotFound(t, app, "/notDefined/livez") } -func Test_HealthCheck_Group_Default(t *testing.T) { - t.Parallel() - - app := fiber.New() - app.Group("/v1", New()) - v2Group := app.Group("/v2/") - customer := v2Group.Group("/customer/") - customer.Use(New()) - - v3Group := app.Group("/v3/") - v3Group.Group("/todos/", New(Config{ReadinessEndpoint: "/readyz/", LivenessEndpoint: "/livez/"})) - - // Testing health check endpoints in versioned API groups - shouldGiveOK(t, app, "/v1/readyz") - shouldGiveOK(t, app, "/v1/livez") - shouldGiveOK(t, app, "/v1/readyz/") - shouldGiveOK(t, app, "/v1/livez/") - shouldGiveOK(t, app, "/v2/customer/readyz") - shouldGiveOK(t, app, "/v2/customer/livez") - shouldGiveOK(t, app, "/v2/customer/readyz/") - shouldGiveOK(t, app, "/v2/customer/livez/") - shouldGiveNotFound(t, app, "/v3/todos/readyz") - shouldGiveNotFound(t, app, "/v3/todos/livez") - shouldGiveOK(t, app, "/v3/todos/readyz/") - shouldGiveOK(t, app, "/v3/todos/livez/") - shouldGiveNotFound(t, app, "/notDefined/readyz") - shouldGiveNotFound(t, app, "/notDefined/livez") - shouldGiveNotFound(t, app, "/notDefined/readyz/") - shouldGiveNotFound(t, app, "/notDefined/livez/") - - // strict routing - app = fiber.New(fiber.Config{ - StrictRouting: true, - }) - app.Group("/v1", New()) - v2Group = app.Group("/v2/") - customer = v2Group.Group("/customer/") - customer.Use(New()) - - v3Group = app.Group("/v3/") - v3Group.Group("/todos/", New(Config{ReadinessEndpoint: "/readyz/", LivenessEndpoint: "/livez/"})) - - shouldGiveOK(t, app, "/v1/readyz") - shouldGiveOK(t, app, "/v1/livez") - shouldGiveNotFound(t, app, "/v1/readyz/") - shouldGiveNotFound(t, app, "/v1/livez/") - shouldGiveOK(t, app, "/v2/customer/readyz") - shouldGiveOK(t, app, "/v2/customer/livez") - shouldGiveNotFound(t, app, "/v2/customer/readyz/") - shouldGiveNotFound(t, app, "/v2/customer/livez/") - shouldGiveNotFound(t, app, "/v3/todos/readyz") - shouldGiveNotFound(t, app, "/v3/todos/livez") - shouldGiveOK(t, app, "/v3/todos/readyz/") - shouldGiveOK(t, app, "/v3/todos/livez/") - shouldGiveNotFound(t, app, "/notDefined/readyz") - shouldGiveNotFound(t, app, "/notDefined/livez") - shouldGiveNotFound(t, app, "/notDefined/readyz/") - shouldGiveNotFound(t, app, "/notDefined/livez/") -} - func Test_HealthCheck_Default(t *testing.T) { t.Parallel() app := fiber.New() - app.Use(New()) + app.Get("/livez", NewHealthChecker()) + app.Get("/readyz", NewHealthChecker()) shouldGiveOK(t, app, "/readyz") shouldGiveOK(t, app, "/livez") @@ -122,14 +64,14 @@ func Test_HealthCheck_Custom(t *testing.T) { t.Parallel() app := fiber.New() - c1 := make(chan struct{}, 1) - app.Use(New(Config{ - LivenessProbe: func(_ fiber.Ctx) bool { + app.Get("/live", NewHealthChecker(Config{ + Probe: func(_ fiber.Ctx) bool { return true }, - LivenessEndpoint: "/live", - ReadinessProbe: func(_ fiber.Ctx) bool { + })) + app.Get("/ready", NewHealthChecker(Config{ + Probe: func(_ fiber.Ctx) bool { select { case <-c1: return true @@ -137,7 +79,6 @@ func Test_HealthCheck_Custom(t *testing.T) { return false } }, - ReadinessEndpoint: "/ready", })) // Setup custom liveness and readiness probes to simulate application health status @@ -146,12 +87,12 @@ func Test_HealthCheck_Custom(t *testing.T) { // Live should return 404 with POST request req, err := app.Test(httptest.NewRequest(fiber.MethodPost, "/live", nil)) require.NoError(t, err) - require.Equal(t, fiber.StatusNotFound, req.StatusCode) + require.Equal(t, fiber.StatusMethodNotAllowed, req.StatusCode) // Ready should return 404 with POST request req, err = app.Test(httptest.NewRequest(fiber.MethodPost, "/ready", nil)) require.NoError(t, err) - require.Equal(t, fiber.StatusNotFound, req.StatusCode) + require.Equal(t, fiber.StatusMethodNotAllowed, req.StatusCode) // Ready should return 503 with GET request before the channel is closed shouldGiveStatus(t, app, "/ready", fiber.StatusServiceUnavailable) @@ -167,13 +108,13 @@ func Test_HealthCheck_Custom_Nested(t *testing.T) { app := fiber.New() c1 := make(chan struct{}, 1) - - app.Use(New(Config{ - LivenessProbe: func(_ fiber.Ctx) bool { + app.Get("/probe/live", NewHealthChecker(Config{ + Probe: func(_ fiber.Ctx) bool { return true }, - LivenessEndpoint: "/probe/live", - ReadinessProbe: func(_ fiber.Ctx) bool { + })) + app.Get("/probe/ready", NewHealthChecker(Config{ + Probe: func(_ fiber.Ctx) bool { select { case <-c1: return true @@ -181,7 +122,6 @@ func Test_HealthCheck_Custom_Nested(t *testing.T) { return false } }, - ReadinessEndpoint: "/probe/ready", })) // Testing custom health check endpoints with nested paths @@ -209,12 +149,17 @@ func Test_HealthCheck_Next(t *testing.T) { app := fiber.New() - app.Use(New(Config{ + checker := NewHealthChecker(Config{ Next: func(_ fiber.Ctx) bool { return true }, - })) + }) + app.Get("/readyz", checker) + app.Get("/livez", checker) + + // This should give not found since there are no other handlers to execute + // so it's like the route isn't defined at all shouldGiveNotFound(t, app, "/readyz") shouldGiveNotFound(t, app, "/livez") } @@ -222,7 +167,8 @@ func Test_HealthCheck_Next(t *testing.T) { func Benchmark_HealthCheck(b *testing.B) { app := fiber.New() - app.Use(New()) + app.Get(DefaultLivenessEndpoint, NewHealthChecker()) + app.Get(DefaultReadinessEndpoint, NewHealthChecker()) h := app.Handler() fctx := &fasthttp.RequestCtx{} @@ -238,3 +184,25 @@ func Benchmark_HealthCheck(b *testing.B) { require.Equal(b, fiber.StatusOK, fctx.Response.Header.StatusCode()) } + +func Benchmark_HealthCheck_Parallel(b *testing.B) { + app := fiber.New() + + app.Get(DefaultLivenessEndpoint, NewHealthChecker()) + app.Get(DefaultReadinessEndpoint, NewHealthChecker()) + + h := app.Handler() + + b.ReportAllocs() + b.ResetTimer() + + b.RunParallel(func(pb *testing.PB) { + fctx := &fasthttp.RequestCtx{} + fctx.Request.Header.SetMethod(fiber.MethodGet) + fctx.Request.SetRequestURI("/livez") + + for pb.Next() { + h(fctx) + } + }) +}