Skip to content

fix(timeout): Return immediately on timeout and propagate context correctly#4009

Merged
ReneWerner87 merged 21 commits into
mainfrom
fix/timeout-immediate-return-and-context-propagation
Jan 21, 2026
Merged

fix(timeout): Return immediately on timeout and propagate context correctly#4009
ReneWerner87 merged 21 commits into
mainfrom
fix/timeout-immediate-return-and-context-propagation

Conversation

@ReneWerner87
Copy link
Copy Markdown
Member

Summary

Replace #3680
Replace #3826

Changes

  • Run handler in goroutine to enable immediate timeout response
  • Keep context.WithTimeout (unlike fix up timeout middleware #3826 which used time.After) so handlers can detect cancellation
  • Add panic recovery that converts panics to 500 Internal Server Error
  • Simplify code by merging runHandler and isCustomError into single isTimeoutError function
  • Update documentation in docs/middleware/timeout.md and docs/whats_new.md

Breaking Changes

None - The API remains the same, but behavior is improved:

  • Clients now receive timeout responses immediately instead of waiting for handler completion
  • Panics in handlers now return 500 instead of crashing

Test Plan

  • TestTimeout_ImmediateReturn - Verifies immediate response on timeout
  • TestTimeout_ContextPropagation - Verifies handler can detect context cancellation
  • TestTimeout_PanicInHandler - Verifies panic handling
  • TestTimeout_PanicAfterTimeout - Verifies late panics don't affect response
  • All existing tests pass

Closes #3671
Closes #3394

Copilot AI review requested due to automatic review settings January 15, 2026 13:05
@ReneWerner87 ReneWerner87 requested a review from a team as a code owner January 15, 2026 13:05
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 15, 2026

Warning

Rate limit exceeded

@ReneWerner87 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 7 minutes and 48 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 95c7456 and 8f0ce51.

📒 Files selected for processing (6)
  • ctx.go
  • ctx_interface.go
  • ctx_interface_gen.go
  • docs/middleware/timeout.md
  • middleware/timeout/timeout.go
  • middleware/timeout/timeout_test.go

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

This change reworks the timeout middleware to run handlers in a separate goroutine and introduce an "Abandon" lifecycle for contexts: on timeout the middleware returns immediately (using OnTimeout or 408), marks the context abandoned, lets the handler finish asynchronously, and provides cleanup/force-release APIs (Abandon(), IsAbandoned(), ForceRelease()).

Changes

Cohort / File(s) Summary
Timeout middleware implementation
middleware/timeout/timeout.go
Runs handler in a goroutine racing a timeout; detects timeouts via context errors, calls Abandon() on timeout, spawns cleanup goroutine, invokes OnTimeout or returns fiber.ErrRequestTimeout, and catches handler panics.
Timeout middleware tests
middleware/timeout/timeout_test.go
Adds many tests (context propagation, early-cancel, immediate return, panic handling, abandon/cleanup, custom OnTimeout, edge cases) and uses sync/atomic for state assertions.
Context lifecycle and interfaces
ctx.go, ctx_interface.go, ctx_interface_gen.go
Adds atomic abandoned flag to DefaultCtx and three new methods: Abandon(), IsAbandoned(), ForceRelease(); changes generated Release() → unexported release() in interface and updates pooling behavior to respect abandonment.
Documentation & migration notes
docs/middleware/timeout.md, docs/whats_new.md, docs/api/ctx.md
Documents Abandon mechanism, context propagation (c.Context().Done()), panic handling, migration to timeout.Config-based New, and documents new Ctx methods with usage cautions.
Context tests
ctx_test.go
Adds tests verifying that Abandon() prevents pooling and that ForceRelease() clears abandoned state and returns contexts to the pool.
Misc
.gitignore
Adds .gocache to .gitignore.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant Middleware as Timeout Middleware
    participant Handler as Handler Goroutine
    participant Cleanup as Cleanup Goroutine
    participant Pool as Context Pool

    Client->>Middleware: HTTP Request
    Middleware->>Middleware: start timeout timer
    Middleware->>Handler: start handler in goroutine (ctx with timeout)
    alt Handler completes before timeout
        Handler->>Middleware: handler result (or panic)
        Middleware->>Client: return handler response (or 500 on panic)
        Middleware->>Pool: release context (abandoned == false)
    else Timeout expires first
        Middleware->>Middleware: call Abandon() on ctx, mark timed out
        Middleware->>Client: return OnTimeout result or 408 immediately
        Middleware->>Cleanup: spawn cleanup goroutine to wait for handler
        Handler->>Handler: continues running (can observe c.Context().Done())
        Handler->>Cleanup: handler finishes
        Cleanup->>Cleanup: clear abandoned flag / call ForceRelease()
        Cleanup->>Pool: return context to pool
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • gaby
  • sixcolors
  • efectn

Poem

🐰 I marked the ctx as gone and hopped off to play,
The client got its answer while handlers finish away.
Cleanup hums behind the scenes, the pool awaits its cue,
ForceRelease clears my footprints, the context comes back new. 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly summarizes the main changes: returning immediately on timeout and fixing context propagation.
Description check ✅ Passed Description covers main issues fixed, architectural changes, breaking changes, and test plan. Missing some checklist items (benchmarks, API alignment) but core content is complete.
Linked Issues check ✅ Passed PR addresses both linked issues: #3671 (context propagation via c.Context().Done()) and #3394 (immediate timeout response even if handler continues).
Out of Scope Changes check ✅ Passed All changes are scoped to timeout middleware behavior, context lifecycle management, and related documentation/tests. No unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @ReneWerner87, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the timeout middleware by improving its responsiveness and robustness. It ensures that clients receive immediate timeout responses, correctly propagates context cancellation to allow handlers to react gracefully, and introduces panic recovery to prevent server crashes from unhandled errors within handlers. These changes collectively lead to a more reliable and predictable middleware behavior.

Highlights

  • Immediate Timeout Response: The timeout middleware now returns immediately when the timeout expires, ensuring clients receive a timely 408 Request Timeout response, even if the underlying handler is still executing. This addresses issue 🐛 [Bug]: Timeout middleware needs to be redesigned #3394.
  • Correct Context Propagation: The context.WithTimeout is properly propagated to the handler, allowing handlers to detect cancellation by listening on c.Context().Done(). This resolves issue 🐛 [Bug]: timeout is not actually enforced #3671.
  • Panic Handling: Panics occurring within the handler are now caught by the middleware and converted into a 500 Internal Server Error response, preventing application crashes.
  • Code Simplification: The internal logic has been refactored, merging runHandler and isCustomError into a single isTimeoutError function for improved clarity and maintainability.
  • Documentation Updates: The documentation in docs/middleware/timeout.md and docs/whats_new.md has been updated to reflect these new behavioral changes and improvements.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request does a great job of fixing the timeout middleware's behavior to return immediately and propagate context correctly. The changes are well-documented and thoroughly tested. My review includes a suggestion to refactor the main select block in the middleware. This refactoring aims to reduce code duplication, ensure the OnTimeout handler receives the correct context, and make the logic for handling timeouts more consistent and maintainable.

Comment thread middleware/timeout/timeout.go
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes timeout middleware behavior to return immediately when a timeout expires (previously waited for handler completion) and ensures proper context propagation so handlers can detect cancellation. It also adds panic recovery that converts handler panics to 500 errors.

Changes:

  • Handler execution now runs in a goroutine with select-based timeout handling
  • Panic recovery added with conversion to fiber.ErrInternalServerError
  • Test coverage enhanced with new tests for immediate return, context propagation, and panic handling

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
middleware/timeout/timeout.go Refactored to run handler in goroutine with select statement for immediate timeout response; added panic recovery; merged helper functions into isTimeoutError
middleware/timeout/timeout_test.go Added comprehensive tests for immediate return, context propagation, panic handling, and converted shared state variables to atomic types for thread safety
docs/middleware/timeout.md Added documentation about immediate return behavior, context cancellation detection, and panic handling
docs/whats_new.md Added behavioral change notes in two sections documenting immediate response, context propagation, and panic handling

Comment thread middleware/timeout/timeout.go
Comment thread middleware/timeout/timeout.go Outdated
Comment thread middleware/timeout/timeout_test.go Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@middleware/timeout/timeout_test.go`:
- Around line 290-313: Add t.Parallel() as the first statement in the
TestIsTimeoutError_WithOnTimeout test to run it concurrently; edit the
TestIsTimeoutError_WithOnTimeout function and insert t.Parallel() immediately
after the function signature so the test follows the repository's parallel test
guideline.
🧹 Nitpick comments (1)
middleware/timeout/timeout.go (1)

64-69: Consider logging the panic value for debugging.

The panic is correctly caught and converted to a 500 error, but the panic value itself is discarded. For debugging purposes, consider logging the panic value before returning.

🔧 Optional: Log panic for debugging
-	case <-panicChan:
+	case p := <-panicChan:
 		// Handler panicked - treat as internal server error
-		// We don't re-panic because we're in a different goroutine context
+		// Log the panic for debugging but don't re-panic
+		// Note: Consider using fiber's logger here if available
+		_ = p // panic value available for logging if needed
 		cancel()
 		ctx.SetContext(parent)
 		return fiber.ErrInternalServerError
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b868148 and 2bfe431.

📒 Files selected for processing (4)
  • docs/middleware/timeout.md
  • docs/whats_new.md
  • middleware/timeout/timeout.go
  • middleware/timeout/timeout_test.go
🧰 Additional context used
📓 Path-based instructions (4)
docs/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Review and update the contents of the docs folder if necessary when modifying code

Files:

  • docs/whats_new.md
  • docs/middleware/timeout.md
**/*.md

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run make markdown to lint all Markdown files when modifying code

Files:

  • docs/whats_new.md
  • docs/middleware/timeout.md
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Prefer github.com/gofiber/utils/v2 helpers (for example, utils.Trim) when performing common operations such as string manipulation, whenever it is practical and appropriate for the surrounding code

Files:

  • middleware/timeout/timeout.go
  • middleware/timeout/timeout_test.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

When adding Go tests, always invoke t.Parallel() at the start of each test and subtest to maximize concurrency

Files:

  • middleware/timeout/timeout_test.go
🧠 Learnings (12)
📓 Common learnings
Learnt from: efectn
Repo: gofiber/fiber PR: 3162
File: app_test.go:893-895
Timestamp: 2024-11-29T12:37:27.581Z
Learning: In the `Test_App_ShutdownWithContext` function in `app_test.go`, the `clientDone` channel is used to synchronize the client's request completion before proceeding, eliminating the need for additional `time.Sleep` calls.
📚 Learning: 2024-11-10T23:44:13.704Z
Learnt from: gaby
Repo: gofiber/fiber PR: 3193
File: middleware/adaptor/adaptor.go:111-111
Timestamp: 2024-11-10T23:44:13.704Z
Learning: In the `middleware/adaptor/adaptor.go` file of the Fiber framework, when updating context handling, replacing `c.Context()` with `c.RequestCtx()` is appropriate to access the `fasthttp.RequestCtx`.

Applied to files:

  • middleware/timeout/timeout.go
📚 Learning: 2024-11-08T04:10:42.990Z
Learnt from: gaby
Repo: gofiber/fiber PR: 3193
File: middleware/cache/cache_test.go:897-897
Timestamp: 2024-11-08T04:10:42.990Z
Learning: In the Fiber framework, `Context()` is being renamed to `RequestCtx()`, and `UserContext()` to `Context()` to improve clarity and align with Go's context conventions.

Applied to files:

  • middleware/timeout/timeout.go
📚 Learning: 2024-11-29T12:37:27.581Z
Learnt from: efectn
Repo: gofiber/fiber PR: 3162
File: app_test.go:893-895
Timestamp: 2024-11-29T12:37:27.581Z
Learning: In the `Test_App_ShutdownWithContext` function in `app_test.go`, the `clientDone` channel is used to synchronize the client's request completion before proceeding, eliminating the need for additional `time.Sleep` calls.

Applied to files:

  • middleware/timeout/timeout.go
  • middleware/timeout/timeout_test.go
📚 Learning: 2024-10-12T10:01:44.206Z
Learnt from: sixcolors
Repo: gofiber/fiber PR: 3016
File: middleware/session/middleware_test.go:190-191
Timestamp: 2024-10-12T10:01:44.206Z
Learning: When testing session `IdleTimeout` expiration, it's acceptable to use `time.Sleep` to simulate the passage of time in tests.

Applied to files:

  • middleware/timeout/timeout_test.go
📚 Learning: 2024-10-08T19:06:06.583Z
Learnt from: sixcolors
Repo: gofiber/fiber PR: 2922
File: middleware/cors/utils.go:63-71
Timestamp: 2024-10-08T19:06:06.583Z
Learning: The project uses the testify/assert package for assertions in unit tests.

Applied to files:

  • middleware/timeout/timeout_test.go
📚 Learning: 2025-10-16T07:19:52.418Z
Learnt from: grivera64
Repo: gofiber/fiber PR: 3807
File: adapter_test.go:118-144
Timestamp: 2025-10-16T07:19:52.418Z
Learning: In the Fiber codebase, the linter does not allow `require` assertions from within HTTP handlers (including net/http-style handlers). Use `t.Fatalf`, `t.Errorf`, or similar `testing.T` methods for error handling inside handler functions instead.

Applied to files:

  • middleware/timeout/timeout_test.go
📚 Learning: 2024-10-08T19:06:06.583Z
Learnt from: sixcolors
Repo: gofiber/fiber PR: 3016
File: middleware/session/store.go:164-167
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Unit tests in this project use testify require.

Applied to files:

  • middleware/timeout/timeout_test.go
📚 Learning: 2024-12-13T08:14:22.851Z
Learnt from: efectn
Repo: gofiber/fiber PR: 3162
File: hooks_test.go:228-228
Timestamp: 2024-12-13T08:14:22.851Z
Learning: In Go test files, prefer using the `require` methods from the `testify` package for assertions instead of manual comparisons and calls to `t.Fatal` or `t.Fatalf`.

Applied to files:

  • middleware/timeout/timeout_test.go
📚 Learning: 2025-12-07T15:07:23.885Z
Learnt from: CR
Repo: gofiber/fiber PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T15:07:23.885Z
Learning: Applies to **/*_test.go : When adding Go tests, always invoke `t.Parallel()` at the start of each test and subtest to maximize concurrency

Applied to files:

  • middleware/timeout/timeout_test.go
📚 Learning: 2024-10-08T19:06:06.583Z
Learnt from: sixcolors
Repo: gofiber/fiber PR: 3051
File: middleware/session/session.go:215-216
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Parallel tests for `Session.Save` already exist in the `middleware/session/session_test.go` file, specifically in the `Test_Session_Save` and `Test_Session_Save_Expiration` functions.

Applied to files:

  • middleware/timeout/timeout_test.go
📚 Learning: 2024-09-25T16:18:34.719Z
Learnt from: sixcolors
Repo: gofiber/fiber PR: 3016
File: middleware/session/config.go:122-122
Timestamp: 2024-09-25T16:18:34.719Z
Learning: In `DefaultErrorHandler(c *fiber.Ctx, err error)`, since `c` is a pointer to an interface, we need to dereference `*c` when calling interface methods like `SendStatus`.

Applied to files:

  • middleware/timeout/timeout_test.go
🧬 Code graph analysis (2)
middleware/timeout/timeout.go (1)
constants.go (2)
  • ErrRequestTimeout (126-126)
  • ErrInternalServerError (148-148)
middleware/timeout/timeout_test.go (2)
middleware/timeout/config.go (1)
  • Config (10-26)
constants.go (2)
  • StatusRequestTimeout (81-81)
  • StatusInternalServerError (103-103)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Cleanup artifacts
  • GitHub Check: repeated
  • GitHub Check: Compare
🔇 Additional comments (12)
docs/middleware/timeout.md (2)

11-15: LGTM! Documentation accurately describes the new behavior.

The added documentation clearly explains:

  • Immediate return on timeout expiration
  • Context propagation via c.Context().Done()
  • Panic handling returning 500 Internal Server Error

This aligns well with the implementation changes in timeout.go.


17-21: Clear and important usage guidance.

The caution block appropriately warns users about the middleware's constraints—specifically that it wraps the final handler and that calling c.Next() will panic.

docs/whats_new.md (2)

1577-1582: LGTM! Behavioral changes are well documented.

The documentation clearly communicates the three key behavioral changes:

  1. Immediate response on timeout
  2. Context propagation via c.Context().Done()
  3. Panic handling returning 500 Internal Server Error

This provides users with clear expectations when upgrading.


2850-2855: Consistent with the earlier section.

The migration guide appropriately repeats the behavioral changes to ensure users migrating from v2 are aware of these important differences. The content is consistent with the "What's New" section.

middleware/timeout/timeout.go (4)

33-35: Correct use of buffered channels.

The buffered channels with size 1 ensure the handler goroutine can complete its send without blocking, even if the middleware has already returned due to timeout. This prevents goroutine leaks.


38-45: LGTM! Proper goroutine-based execution with panic recovery.

The pattern correctly:

  1. Runs the handler in a separate goroutine for non-blocking timeout enforcement
  2. Uses defer with recover() to catch panics
  3. Sends either the panic value or handler result to the appropriate channel

This allows the middleware to return immediately on timeout regardless of handler behavior.


85-99: LGTM! Clean helper function.

The isTimeoutError function correctly:

  1. Uses errors.Is to handle wrapped errors
  2. Checks context.DeadlineExceeded first (most common case)
  3. Iterates custom errors only when the slice is non-empty

71-80: This is the intended design—no changes needed.

The middleware correctly handles concurrent context access. When timeout occurs, the handler goroutine may still be running, but this is expected and documented behavior. Tests (TestTimeout_ImmediateReturn, TestTimeout_PanicAfterTimeout) confirm that:

  1. The response returns immediately on timeout, even if the handler continues running in the background.
  2. Handlers can detect the timeout by checking c.Context().Done().
  3. Panics or continued execution after timeout don't affect the response that was already sent.

The thread-safety is guaranteed because fasthttp.UserValue operations (used by SetContext and Context) are thread-safe, and the response is sent before the handler continues.

middleware/timeout/timeout_test.go (4)

83-107: Excellent test for Issue #3394.

This test validates the key behavioral change—that the middleware returns immediately on timeout even when the handler doesn't check the context. Good use of atomic.Bool for thread-safe assertion.


111-137: Good test for Issue #3671.

This test validates context propagation—that handlers can detect timeout via c.Context().Done(). The time.Sleep(20 * time.Millisecond) is acceptable here to allow the handler goroutine to process the cancellation before assertion.


239-269: Comprehensive panic handling tests.

Both tests properly validate the panic recovery behavior:

  1. TestTimeout_PanicInHandler: Verifies immediate panics return 500
  2. TestTimeout_PanicAfterTimeout: Verifies late panics (after timeout response) don't affect the response

316-334: LGTM! Good test for Next() skip functionality.

This test verifies that when Next returns true, the timeout middleware is bypassed and the handler runs without timeout constraints.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment thread middleware/timeout/timeout_test.go
@github-project-automation github-project-automation Bot moved this to Done in v3 Jan 15, 2026
@ReneWerner87 ReneWerner87 reopened this Jan 15, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 15, 2026

Codecov Report

❌ Patch coverage is 96.72131% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.18%. Comparing base (9e1cf4d) to head (8f0ce51).
⚠️ Report is 39 commits behind head on main.

Files with missing lines Patch % Lines
middleware/timeout/timeout.go 96.15% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4009   +/-   ##
=======================================
  Coverage   91.17%   91.18%           
=======================================
  Files         119      119           
  Lines       10946    10987   +41     
=======================================
+ Hits         9980    10018   +38     
- Misses        609      612    +3     
  Partials      357      357           
Flag Coverage Δ
unittests 91.18% <96.72%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@middleware/timeout/timeout.go`:
- Around line 47-70: Fix the misspelled words in the comments around the timeout
handling block: update comment text near the select/done/panicChan logic and the
line "// Check if timeout occurred BEFORE cancelling (cancel() would set Err())"
to use correct spelling and style (e.g., "occurred" and the preferred
"canceling" or your repo's convention), keeping the surrounding logic intact
(tCtx, done, panicChan, cancel(), ctx.SetContext(parent), panicked). Ensure
comments are concise, correctly spelled, and do not change runtime behavior.
♻️ Duplicate comments (1)
middleware/timeout/timeout_test.go (1)

272-296: Missing t.Parallel() call.

Per coding guidelines, all tests should invoke t.Parallel() at the start to maximize concurrency.

🔧 Proposed fix
 // TestIsTimeoutError_WithOnTimeout verifies that custom OnTimeout is called for custom errors.
 func TestIsTimeoutError_WithOnTimeout(t *testing.T) {
+	t.Parallel()
 	app := fiber.New()
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2bfe431 and 66f5528.

📒 Files selected for processing (4)
  • docs/middleware/timeout.md
  • docs/whats_new.md
  • middleware/timeout/timeout.go
  • middleware/timeout/timeout_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/whats_new.md
🧰 Additional context used
📓 Path-based instructions (4)
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

When adding Go tests, always invoke t.Parallel() at the start of each test and subtest to maximize concurrency

Files:

  • middleware/timeout/timeout_test.go
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Prefer github.com/gofiber/utils/v2 helpers (for example, utils.Trim) when performing common operations such as string manipulation, whenever it is practical and appropriate for the surrounding code

Files:

  • middleware/timeout/timeout_test.go
  • middleware/timeout/timeout.go
docs/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Review and update the contents of the docs folder if necessary when modifying code

Files:

  • docs/middleware/timeout.md
**/*.md

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run make markdown to lint all Markdown files when modifying code

Files:

  • docs/middleware/timeout.md
🧠 Learnings (11)
📓 Common learnings
Learnt from: sixcolors
Repo: gofiber/fiber PR: 3016
File: middleware/session/middleware_test.go:190-191
Timestamp: 2024-10-12T10:01:44.206Z
Learning: When testing session `IdleTimeout` expiration, it's acceptable to use `time.Sleep` to simulate the passage of time in tests.
Learnt from: sixcolors
Repo: gofiber/fiber PR: 3016
File: middleware/session/middleware_test.go:190-191
Timestamp: 2024-09-25T17:05:06.991Z
Learning: When testing session `IdleTimeout` expiration, it's acceptable to use `time.Sleep` to simulate the passage of time in tests.
Learnt from: efectn
Repo: gofiber/fiber PR: 3162
File: app_test.go:893-895
Timestamp: 2024-11-29T12:37:27.581Z
Learning: In the `Test_App_ShutdownWithContext` function in `app_test.go`, the `clientDone` channel is used to synchronize the client's request completion before proceeding, eliminating the need for additional `time.Sleep` calls.
📚 Learning: 2024-10-12T10:01:44.206Z
Learnt from: sixcolors
Repo: gofiber/fiber PR: 3016
File: middleware/session/middleware_test.go:190-191
Timestamp: 2024-10-12T10:01:44.206Z
Learning: When testing session `IdleTimeout` expiration, it's acceptable to use `time.Sleep` to simulate the passage of time in tests.

Applied to files:

  • middleware/timeout/timeout_test.go
📚 Learning: 2025-12-07T15:07:23.885Z
Learnt from: CR
Repo: gofiber/fiber PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T15:07:23.885Z
Learning: Applies to **/*_test.go : When adding Go tests, always invoke `t.Parallel()` at the start of each test and subtest to maximize concurrency

Applied to files:

  • middleware/timeout/timeout_test.go
📚 Learning: 2024-11-29T12:37:27.581Z
Learnt from: efectn
Repo: gofiber/fiber PR: 3162
File: app_test.go:893-895
Timestamp: 2024-11-29T12:37:27.581Z
Learning: In the `Test_App_ShutdownWithContext` function in `app_test.go`, the `clientDone` channel is used to synchronize the client's request completion before proceeding, eliminating the need for additional `time.Sleep` calls.

Applied to files:

  • middleware/timeout/timeout_test.go
  • middleware/timeout/timeout.go
📚 Learning: 2025-10-16T07:19:52.418Z
Learnt from: grivera64
Repo: gofiber/fiber PR: 3807
File: adapter_test.go:118-144
Timestamp: 2025-10-16T07:19:52.418Z
Learning: In the Fiber codebase, the linter does not allow `require` assertions from within HTTP handlers (including net/http-style handlers). Use `t.Fatalf`, `t.Errorf`, or similar `testing.T` methods for error handling inside handler functions instead.

Applied to files:

  • middleware/timeout/timeout_test.go
📚 Learning: 2024-10-08T19:06:06.583Z
Learnt from: sixcolors
Repo: gofiber/fiber PR: 2922
File: middleware/cors/utils.go:63-71
Timestamp: 2024-10-08T19:06:06.583Z
Learning: The project uses the testify/assert package for assertions in unit tests.

Applied to files:

  • middleware/timeout/timeout_test.go
📚 Learning: 2024-10-08T19:06:06.583Z
Learnt from: sixcolors
Repo: gofiber/fiber PR: 3016
File: middleware/session/store.go:164-167
Timestamp: 2024-10-08T19:06:06.583Z
Learning: Unit tests in this project use testify require.

Applied to files:

  • middleware/timeout/timeout_test.go
📚 Learning: 2024-12-13T08:14:22.851Z
Learnt from: efectn
Repo: gofiber/fiber PR: 3162
File: hooks_test.go:228-228
Timestamp: 2024-12-13T08:14:22.851Z
Learning: In Go test files, prefer using the `require` methods from the `testify` package for assertions instead of manual comparisons and calls to `t.Fatal` or `t.Fatalf`.

Applied to files:

  • middleware/timeout/timeout_test.go
📚 Learning: 2024-10-08T19:06:06.583Z
Learnt from: sixcolors
Repo: gofiber/fiber PR: 3016
File: middleware/session/config.go:122-122
Timestamp: 2024-10-08T19:06:06.583Z
Learning: In `DefaultErrorHandler(c *fiber.Ctx, err error)`, since `c` is a pointer to an interface, we need to dereference `*c` when calling interface methods like `SendStatus`.

Applied to files:

  • middleware/timeout/timeout_test.go
  • middleware/timeout/timeout.go
📚 Learning: 2024-11-10T23:44:13.704Z
Learnt from: gaby
Repo: gofiber/fiber PR: 3193
File: middleware/adaptor/adaptor.go:111-111
Timestamp: 2024-11-10T23:44:13.704Z
Learning: In the `middleware/adaptor/adaptor.go` file of the Fiber framework, when updating context handling, replacing `c.Context()` with `c.RequestCtx()` is appropriate to access the `fasthttp.RequestCtx`.

Applied to files:

  • middleware/timeout/timeout.go
📚 Learning: 2024-11-08T04:10:42.990Z
Learnt from: gaby
Repo: gofiber/fiber PR: 3193
File: middleware/cache/cache_test.go:897-897
Timestamp: 2024-11-08T04:10:42.990Z
Learning: In the Fiber framework, `Context()` is being renamed to `RequestCtx()`, and `UserContext()` to `Context()` to improve clarity and align with Go's context conventions.

Applied to files:

  • middleware/timeout/timeout.go
🧬 Code graph analysis (2)
middleware/timeout/timeout_test.go (2)
middleware/timeout/timeout.go (1)
  • New (15-85)
middleware/timeout/config.go (1)
  • Config (10-26)
middleware/timeout/timeout.go (1)
constants.go (2)
  • ErrInternalServerError (148-148)
  • ErrRequestTimeout (126-126)
🪛 GitHub Actions: golangci-lint
middleware/timeout/timeout.go

[error] 60-60: golangci-lint: misspelling 'cancelling' should be 'canceling' (misspell).

🪛 GitHub Check: lint
middleware/timeout/timeout.go

[failure] 72-72:
cancelled is a misspelling of canceled (misspell)


[failure] 60-60:
cancelling is a misspelling of canceling (misspell)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: repeated
  • GitHub Check: unit (1.25.x, macos-latest)
  • GitHub Check: unit (1.25.x, windows-latest)
  • GitHub Check: unit (1.25.x, ubuntu-latest)
  • GitHub Check: lint
  • GitHub Check: Compare
  • GitHub Check: Analyse
  • GitHub Check: Compare
  • GitHub Check: repeated
🔇 Additional comments (15)
middleware/timeout/timeout_test.go (8)

40-57: LGTM!

Test properly validates that handlers completing within the timeout window return successfully. Good use of sleepWithContext helper and proper t.Parallel() invocation.


59-80: LGTM!

This test correctly validates the core timeout behavior. The elapsed time check (line 79) ensures the handler returns early on context cancellation rather than waiting the full 200ms.


82-107: LGTM!

Excellent test for Issue #3671 - properly validates that the timeout context is propagated to handlers so they can detect cancellation via c.Context().Done(). Good use of atomic.Bool for thread-safe state tracking.


109-137: LGTM!

Well-designed test that demonstrates handlers can return early by checking context, making the overall request faster than the handler's potential work time.


212-236: LGTM!

Good use of atomic.Int32 to safely track that the custom handler was called exactly once across goroutines.


238-252: LGTM!

This test validates the new panic recovery behavior - panics in handlers are caught and translated to 500 Internal Server Error instead of crashing the process.


298-317: LGTM!

Good test coverage for the Next function skip behavior, validating that when Next returns true, the middleware is bypassed entirely.


319-336: LGTM!

Important test that validates timeout detection even when the handler returns nil instead of an error - the middleware correctly checks the context state independently.

middleware/timeout/timeout.go (5)

10-14: LGTM!

Clear and accurate documentation of the middleware's behavior - timeout context propagation, detection via c.Context().Done(), and return of fiber.ErrRequestTimeout on deadline exceeded.


18-26: LGTM!

Good handling of the skip path (cfg.Next) and non-positive timeout path - both execute the handler directly without the timeout orchestration overhead.


28-45: LGTM!

Well-structured concurrent execution model:

  • Timeout context properly created and exposed via ctx.SetContext(tCtx)
  • Buffered channels (size 1) prevent goroutine leaks when the receiver has already returned
  • Panic recovery in the deferred function catches panics and sends to panicChan

72-84: LGTM!

Timeout handling logic is correct:

  • Checks both contextTimedOut flag and isTimeoutError for comprehensive detection
  • Properly invokes OnTimeout if configured and propagates its error
  • Falls back to fiber.ErrRequestTimeout as the default timeout response

87-101: LGTM!

Clean helper function that correctly identifies timeout-like errors using errors.Is for proper error chain unwrapping. Handles both context.DeadlineExceeded and custom configured errors.

docs/middleware/timeout.md (2)

11-15: LGTM!

Documentation accurately reflects the new middleware behavior:

  • Context cancellation detection via c.Context().Done()
  • 408 response on timeout
  • Panic handling returning 500 Internal Server Error

This aligns well with the implementation in timeout.go.


50-76: LGTM!

Excellent example demonstrating the recommended pattern for timeout-aware handlers using sleepWithContext. This clearly shows how handlers should check ctx.Done() to cooperate with the timeout middleware.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment thread middleware/timeout/timeout.go Outdated
github-actions[bot]

This comment was marked as off-topic.

@ReneWerner87
Copy link
Copy Markdown
Member Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the timeout middleware to correctly propagate the timeout context and to handle panics within handlers by returning a 500 error. The implementation now runs the handler in a separate goroutine to facilitate panic recovery. While this is a good improvement for robustness, I've identified a critical issue where the middleware does not actually time out if the handler is non-cooperative and blocks indefinitely. This can lead to resource exhaustion. I've added a critical review comment on this matter and a suggestion to add a test case that makes this limitation explicit.

Comment thread middleware/timeout/timeout.go
@ReneWerner87
Copy link
Copy Markdown
Member Author

@copilot review

@pjebs
Copy link
Copy Markdown
Contributor

pjebs commented Jan 17, 2026

Why the grace period? If the developer wants a "grace period", they will just increase the timeout value appropriately. The grace period just adds an extra level of uncertainty where you need to look at the code to see what the value is and how it works.

If it's the avoid race conditions - then it's not avoiding race conditions. It's just minimising the probability of race conditions happening. Not eliminating it.

@pjebs
Copy link
Copy Markdown
Contributor

pjebs commented Jan 17, 2026

The documentation says cancellation. The spelling needs to be consistent. Will Fiber use UK or US spelling:

cancellation or cancelation?

@edvardsanta
Copy link
Copy Markdown
Contributor

Thanks for the suggestion @pjebs! I looked into fasthttp's TimeoutHandler and TimeoutErrorWithResponse in detail togehter with my AI agent. Here's why we can't directly use them to solve the race condition problem:

How fasthttp's TimeoutHandler works

Looking at the fasthttp source (server.go:459-491), TimeoutWithCodeHandler does the following:

func TimeoutWithCodeHandler(h RequestHandler, timeout time.Duration, msg string, statusCode int) RequestHandler {
    return func(ctx *RequestCtx) {
        // 1. Run handler in goroutine
        go func() {
            h(ctx)
            ch <- struct{}{}
        }()

        // 2. Wait for handler OR timeout
        select {
        case <-ch:
            // Handler finished
        case <-ctx.timeoutTimer.C:
            ctx.TimeoutErrorWithCode(msg, statusCode)
        }
    }
}

The key mechanism is in serveConn (line 2468-2473):

timeoutResponse = ctx.timeoutResponse
if timeoutResponse != nil {
    // Acquire a NEW ctx because the old one will still be in use by the handler
    ctx = s.acquireCtx(c)
    timeoutResponse.CopyTo(&ctx.Response)
}

fasthttp acquires a new RequestCtx and lets the old one continue for the still-running handler. This is how it avoids race conditions at the fasthttp level.

Why this doesn't work for Fiber

The problem is that Fiber has its own fiber.Ctx wrapper around *fasthttp.RequestCtx:
Aspect fasthttp Fiber
Context type *fasthttp.RequestCtx fiber.Ctx (wrapper)
New ctx on timeout ✅ fasthttp acquires new RequestCtx ❌ Fiber's Ctx remains the same
Handler reference Points to old RequestCtx (safe, new one is used for response) Points to fiber.Ctx which wraps the old RequestCtx

When TimeoutErrorWithResponse is called:

1. It only marks the **fasthttp Response** for replacement

2. fasthttp acquires a new `RequestCtx` for the response

3. **But**: The handler still has `fiber.Ctx`, which points to the old `RequestCtx`

4. If the handler accesses `fiber.Ctx` after timeout (`ctx.Locals()`, `ctx.Context()`, `ctx.SetContext()`, etc.), race conditions occur

TimeoutErrorWithResponse protects the fasthttp Response, not the entire Fiber context. The race conditions happen at the Fiber level, not the fasthttp level.

What would be needed for "true" immediate return

To properly use fasthttp's mechanism, Fiber would need to:

1. Acquire a **new `fiber.Ctx`** on timeout (similar to how fasthttp acquires a new `RequestCtx`)

2. "Abandon" the old `fiber.Ctx` for the handler

3. This requires **Fiber core changes** (context pooling), not just middleware changes

Our current solution

The current implementation uses:

* `context.WithTimeout` so handlers can detect timeout via `c.Context().Done()`

* Goroutine with panic handling

* Bounded grace period (50-100ms) so hung handlers don't block forever

Handlers that check c.Context().Done() can return early and achieve practically the same result as "immediate return" - but in a race-free way.

This is the safest approach without modifying Fiber's core context management.

Let us test the current solutio and if that concept doesn't work as expected, then we'll try an approach that requires us to make core changes. In that case, I like the independent middleware because it's not tightly integrated.

Specifically, the panic-related test cases were problematic. In scenarios where the handler panics after the timeout or where the OnTimeout handler itself panics, I observed concurrency-related issues that I couldn’t safely resolve without deeper changes. These cases were especially tricky due to goroutine lifecycle and race conditions around timeout handling.

func TestTimeout_Issue_3671(t *testing.T) {
	t.Parallel()
	app := fiber.New()
	testCases := []struct {
		name       string
		path       string
		handler    fiber.Handler
		config     Config
		expectCode int
	}{
		{
			name: "Handler panics after timeout",
			path: "/panic-after-timeout",
			handler: func(_ fiber.Ctx) error {
				time.Sleep(50 * time.Millisecond)
				panic("panic after timeout")
			},
			config:     Config{Timeout: 10 * time.Millisecond},
			expectCode: fiber.StatusRequestTimeout,
		},
		{
			name: "Handler blocks forever",
			path: "/block-forever",
			handler: func(_ fiber.Ctx) error {
				select {} // Block forever
			},
			config:     Config{Timeout: 10 * time.Millisecond},
			expectCode: fiber.StatusRequestTimeout,
		},
		{
			name: "Timeout set to 1 nanosecond",
			path: "/nano",
			handler: func(c fiber.Ctx) error {
				time.Sleep(1 * time.Millisecond)
				return c.SendString("late")
			},
			config:     Config{Timeout: 1 * time.Nanosecond},
			expectCode: fiber.StatusRequestTimeout,
		},
		{
			name: "Timeout set to a very large value",
			path: "/maxint",
			handler: func(c fiber.Ctx) error {
				return c.SendString("ok")
			},
			config:     Config{Timeout: 1<<63 - 1},
			expectCode: fiber.StatusOK,
		},
		{
			name: "Custom OnTimeout handler panics",
			path: "/panic-ontimeout",
			handler: func(_ fiber.Ctx) error {
				time.Sleep(50 * time.Millisecond)
				return nil
			},
			config: Config{
				Timeout: 10 * time.Millisecond,
				OnTimeout: func(_ fiber.Ctx) error {
					panic("custom panic on timeout")
				},
			},
			expectCode: fiber.StatusRequestTimeout,
		},
		{
			name: "Custom OnTimeout",
			path: "/ontimeout",
			handler: func(c fiber.Ctx) error {
				if err := sleepWithContext(c.Context(), 100*time.Millisecond, context.DeadlineExceeded); err != nil {
					return err
				}
				return c.SendString("should not reach")
			},
			config: Config{
				Timeout: 20 * time.Millisecond,
				OnTimeout: func(c fiber.Ctx) error {
					return c.SendString("custom timeout response")
				},
			},
			expectCode: fiber.StatusRequestTimeout,
		},
	}

	for _, tc := range testCases {
		app.Get(tc.path, New(tc.handler, tc.config))
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			req := httptest.NewRequest(fiber.MethodGet, tc.path, nil)
			resp, err := app.Test(req)

			require.NoError(t, err)
			require.Equal(t, tc.expectCode, resp.StatusCode)
		})
	}
}

@ReneWerner87
Copy link
Copy Markdown
Member Author

ReneWerner87 commented Jan 18, 2026

@pjebs You're right - the fixed grace period was logically inconsistent. We've changed the approach:

New behavior:

  • GracePeriod: 0 (default): Middleware waits indefinitely for the handler to finish → race-free
  • GracePeriod > 0: Middleware waits at most GracePeriod after timeout → faster response, but potential races

This gives users full control. The default is now the safest option (always wait), and users who want faster responses can
explicitly opt-in to the grace period with full awareness of the trade-offs.

Regarding spelling: I changed the places to US


@edvardsanta Thanks for testing and identifying the concurrency issues with panic scenarios!

The current implementation handles panics by:

  1. Catching them in the handler goroutine via recover()
  2. Returning 500 Internal Server Error
  3. By default (GracePeriod: 0), waiting for the handler to complete - this avoids races even when panics occur after timeout

The tests TestTimeout_PanicInHandler and TestTimeout_PanicAfterTimeout verify this behavior. If you're still seeing issues with specific scenarios, please share the details and we can investigate further.

@pjebs
Copy link
Copy Markdown
Contributor

pjebs commented Jan 18, 2026

I think Fiber internals needs to be rewritten a bit. FastHTTP's timeout middleware doesn't have any race conditions.
According to your comment, the developer has to select a value for the grace period, where they are tolerating a certain probability that they will encounter concurrency related bugs.

@ReneWerner87
Copy link
Copy Markdown
Member Author

@pjebs @edvardsanta
a8da7a0

I have now expanded our core and implemented a race-free approach similar to the fasthttp approach.
I couldn't use the fasthttp approach, otherwise I would have had to make a lot more adjustments, and our fiber approach with the new methods is now also more flexible.

@ReneWerner87
Copy link
Copy Markdown
Member Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a significant improvement to the timeout middleware by allowing it to return immediately when a timeout occurs, which is achieved by running handlers in a separate goroutine. The implementation also adds panic recovery and a new context 'abandon' mechanism to manage context lifecycle in these detached scenarios. My review focuses on a few critical aspects of this new implementation. I've identified a high-severity issue where recovered panics are not logged, making debugging difficult. More critically, the current approach introduces a memory leak for every timed-out request as a trade-off for race safety. While the safety aspect is understood, this is a significant behavioral change that needs to be addressed or at least prominently documented. I've also pointed out that the documentation for the new Abandon/ForceRelease APIs is inconsistent with their actual use in the timeout middleware.

Comment thread middleware/timeout/timeout.go
Comment thread middleware/timeout/timeout.go Outdated
Comment thread ctx.go Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 2 comments.

Comment thread middleware/timeout/timeout_test.go
Comment thread middleware/timeout/timeout.go Outdated
@pjebs
Copy link
Copy Markdown
Contributor

pjebs commented Jan 18, 2026

Maybe you can unexport the Abandon method you just created, and call it using unsafe or reflect.
You may need to convert the method to an unexported function to do that approach.

Others don't need to know about it. The API surface and documentation is already bloated.

@ReneWerner87
Copy link
Copy Markdown
Member Author

Maybe you can unexport the Abandon method you just created, and call it using unsafe or reflect. You may need to convert the method to an unexported function to do that approach.

Others don't need to know about it. The API surface and documentation is already bloated.

its okay like it is

@ReneWerner87 ReneWerner87 merged commit bb7d6d8 into main Jan 21, 2026
18 checks passed
@ReneWerner87 ReneWerner87 deleted the fix/timeout-immediate-return-and-context-propagation branch January 21, 2026 07:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

🐛 [Bug]: timeout is not actually enforced 🐛 [Bug]: Timeout middleware needs to be redesigned

6 participants