Skip to content

fix(docker-mariadb-clean-arch): bound data layer calls with a request context - #5305

Merged
ReneWerner87 merged 3 commits into
masterfrom
claude/mariadb-request-context
Aug 1, 2026
Merged

fix(docker-mariadb-clean-arch): bound data layer calls with a request context#5305
ReneWerner87 merged 3 commits into
masterfrom
claude/mariadb-request-context

Conversation

@ReneWerner87

@ReneWerner87 ReneWerner87 commented Aug 1, 2026

Copy link
Copy Markdown
Member

Closes #2718.

The problem

Every handler and middleware in this recipe passed context.Background() straight through the service into the repository and on to database/sql. Nothing ever set a deadline, so a slow or hung query blocked the handler for as long as the driver kept waiting, and a client that disconnected left the query running.

The issue reported this against context.WithCancel, which the code used in 2023:

customContext, cancel := context.WithCancel(context.Background())
defer cancel()

The reporter was right, and for a sharper reason than they gave. The cancel func was deferred but nothing else could ever trigger it, so it cancelled nothing. The call was later simplified to a plain context.Background(), which removed even that.

The fix

All twelve call sites now derive from the request context and add a deadline:

ctx, cancel := context.WithTimeout(c.Context(), requestTimeout)
defer cancel()

cities, err := h.cityService.FetchCities(ctx)

This covers both halves of the problem, which a bare WithTimeout(context.Background(), ...) would not:

  • c.Context() is cancelled when the client disconnects, so an abandoned request stops occupying a database connection
  • the timeout bounds a query that hangs while the client is still connected

requestTimeout is a package level constant in city and user, set to 10 seconds. Kept per package rather than shared, so the two stay independent as the clean architecture layout intends.

Sites touched: 5 in city/handler.go, 1 in city/middleware.go, 5 in user/handler.go, 1 in user/middleware.go.

On the wontfix label

Worth flagging, since it looks like a maintainer decision and is not one. .github/stale.yml sets staleLabel: wontfix, so the label was applied automatically by the stale bot. All five comments on the issue are bot noise, three welcome-bot and two stale-bot. Nobody ever answered the technical question.

The same applies to #2704, #2705 and #2706, which carry the label for the same reason.

Verification

  • go build ./... passes
  • go vet ./... passes
  • no context.Background() calls remain anywhere in the recipe

Not exercised: the running stack against MariaDB, which needs the docker-compose environment.

Summary by CodeRabbit

  • Bug Fixes
    • Added a 10-second timeout to city and user operations.
    • Requests now stop processing when the client request ends or the timeout is reached.
    • Improved cancellation handling for city and user lookups, creation, updates, and deletions.
    • Query failures encountered while reading city or user results are now reported instead of returning incomplete data as successful responses.

… context

Closes #2718.

Every handler and middleware passed context.Background() straight through
the service into the repository and on to database/sql. Nothing in the
recipe ever set a deadline, so a slow or hung query blocked the handler
for as long as the driver kept waiting, and a client that disconnected
left the query running.

The issue reported this against context.WithCancel, which the code used
at the time. The cancel func was deferred but nothing else could trigger
it, so it never cancelled anything. The call was later simplified to a
plain context.Background(), which removed even that.

All twelve call sites now derive from the request context and add a
deadline:

    ctx, cancel := context.WithTimeout(c.Context(), requestTimeout)
    defer cancel()

That covers both halves of the problem. c.Context() is cancelled when the
client goes away, and the timeout bounds a query that hangs while the
client is still connected. requestTimeout is a package level constant in
city and user, set to 10 seconds, kept per package so the two stay
independent as the clean architecture layout intends.

Verified with go build ./... and go vet ./...; no context.Background()
calls remain in the recipe.
Copilot AI review requested due to automatic review settings August 1, 2026 12:21
Copilot AI previously approved these changes Aug 1, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Ready to approve

The changes are localized and correctly propagate request-scoped timeouts into service calls, with only minor middleware context-cancel timing improvements suggested.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

This PR updates the docker-mariadb-clean-arch recipe to ensure data-layer calls are bounded by request-scoped contexts with deadlines, preventing handlers from hanging indefinitely on slow/hung DB operations and allowing cancellation when the client disconnects.

Changes:

  • Introduced a per-package requestTimeout constant (10s) for city and user.
  • Replaced context.Background() usage in handlers/middleware with context.WithTimeout(c.Context(), requestTimeout) and propagated the derived context into service calls.
  • Updated both city and user middleware to use request-derived contexts when performing existence checks.
File summaries
File Description
docker-mariadb-clean-arch/internal/user/handler.go Adds a 10s request timeout and uses request-derived contexts for all user handler service calls.
docker-mariadb-clean-arch/internal/user/middleware.go Uses a request-derived timeout context for the “user exists” lookup before continuing the chain.
docker-mariadb-clean-arch/internal/city/handler.go Adds a 10s request timeout and uses request-derived contexts for all city handler service calls.
docker-mariadb-clean-arch/internal/city/middleware.go Uses a request-derived timeout context for the “city exists” lookup before continuing the chain.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 2
  • Review effort level: Lite

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment thread docker-mariadb-clean-arch/internal/user/middleware.go
Comment thread docker-mariadb-clean-arch/internal/city/middleware.go
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dbf72b3e-9920-4418-a08c-e4f1c94b2c4f

📥 Commits

Reviewing files that changed from the base of the PR and between c1b2289 and e85abe0.

📒 Files selected for processing (2)
  • docker-mariadb-clean-arch/internal/city/middleware.go
  • docker-mariadb-clean-arch/internal/user/middleware.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • docker-mariadb-clean-arch/internal/city/middleware.go
  • docker-mariadb-clean-arch/internal/user/middleware.go
📜 Recent review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: copilot-pull-request-reviewer
  • GitHub Check: Analyze (go)

📝 Walkthrough

Walkthrough

City and user handlers and middleware now derive 10-second cancellable contexts from Fiber requests. City and user repositories now return database row iteration errors instead of partial results with nil errors.

Changes

Request Timeout Propagation

Layer / File(s) Summary
City timeout and iteration handling
docker-mariadb-clean-arch/internal/city/handler.go, docker-mariadb-clean-arch/internal/city/middleware.go, docker-mariadb-clean-arch/internal/city/repository.go
City operations and lookup middleware use 10-second timeout contexts. GetCities returns row iteration errors.
User timeout and iteration handling
docker-mariadb-clean-arch/internal/user/handler.go, docker-mariadb-clean-arch/internal/user/middleware.go, docker-mariadb-clean-arch/internal/user/repository.go
User operations and lookup middleware use 10-second timeout contexts. GetUsers returns row iteration errors.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: copilot

Poem

A rabbit sets the timer tight,
Ten seconds guide each request’s flight.
City hops and users too,
Row errors now come through.
Cancel when the work is through.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the primary change: bounding data-layer calls with a request-scoped context.
Linked Issues check ✅ Passed The changes satisfy issue #2718 by applying 10-second timeout contexts to all city and user data-layer operations.
Out of Scope Changes check ✅ Passed The repository error checks and immediate context cancellation support the stated timeout and cancellation objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/mariadb-request-context

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
docker-mariadb-clean-arch/internal/city/handler.go (1)

12-16: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the timeout as per operation, not per request.

The existence middleware and the subsequent update or delete handler create independent 10-second contexts. A PUT or DELETE request can therefore spend two sequential 10-second data-layer waits. The comment says the constant bounds one request, which is not accurate. If the requirement is per operation, update the comment. If it is a 10-second total request budget, reuse one context across both calls.

  • docker-mariadb-clean-arch/internal/city/handler.go#L12-L16: describe requestTimeout as an operation timeout, or propagate one request-wide context.
  • docker-mariadb-clean-arch/internal/user/handler.go#L10-L16: apply the same clarification or request-wide context design.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-mariadb-clean-arch/internal/city/handler.go` around lines 12 - 16,
Clarify both requestTimeout comments as per-operation data-layer timeouts rather
than single-request budgets; update
docker-mariadb-clean-arch/internal/city/handler.go lines 12-16 and
docker-mariadb-clean-arch/internal/user/handler.go lines 10-16, with no context
propagation changes required.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docker-mariadb-clean-arch/internal/city/handler.go`:
- Around line 47-50: Add result-error propagation after the row-iteration loops
in GetCities and GetUsers within
docker-mariadb-clean-arch/internal/city/repository.go and
docker-mariadb-clean-arch/internal/user/repository.go, returning res.Err()
instead of the collected slice when iteration is interrupted. The handler sites
docker-mariadb-clean-arch/internal/city/handler.go lines 47-50 and
docker-mariadb-clean-arch/internal/user/handler.go lines 41-44 require no direct
changes; they will propagate the repository errors.

---

Nitpick comments:
In `@docker-mariadb-clean-arch/internal/city/handler.go`:
- Around line 12-16: Clarify both requestTimeout comments as per-operation
data-layer timeouts rather than single-request budgets; update
docker-mariadb-clean-arch/internal/city/handler.go lines 12-16 and
docker-mariadb-clean-arch/internal/user/handler.go lines 10-16, with no context
propagation changes required.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f2817a69-3e4d-4cfa-8cfd-cacb75a9e26c

📥 Commits

Reviewing files that changed from the base of the PR and between 742f322 and a9105c7.

📒 Files selected for processing (4)
  • docker-mariadb-clean-arch/internal/city/handler.go
  • docker-mariadb-clean-arch/internal/city/middleware.go
  • docker-mariadb-clean-arch/internal/user/handler.go
  • docker-mariadb-clean-arch/internal/user/middleware.go
📜 Review details
⏰ Context from checks skipped due to timeout. (4)
  • GitHub Check: copilot-pull-request-reviewer
  • GitHub Check: Analyze (actions)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
🔇 Additional comments (6)
docker-mariadb-clean-arch/internal/city/handler.go (2)

5-10: LGTM!


77-80: LGTM!

Also applies to: 110-113, 144-147, 168-171

docker-mariadb-clean-arch/internal/city/middleware.go (1)

21-24: LGTM!

docker-mariadb-clean-arch/internal/user/handler.go (2)

5-8: LGTM!


71-74: LGTM!

Also applies to: 103-106, 136-139, 160-163

docker-mariadb-clean-arch/internal/user/middleware.go (1)

21-24: LGTM!

Comment thread docker-mariadb-clean-arch/internal/city/handler.go
Raised by CodeRabbit on review, and it is a real consequence of adding
timeouts in the previous commit.

GetCities and GetUsers iterate with res.Next() and return the collected
slice once the loop ends, without checking res.Err(). res.Next() also
returns false when the context is cancelled, so a query that times out or
whose client disconnected mid-iteration produced a partial slice and a nil
error, and the handler answered HTTP 200 with incomplete data.

This was latent before: with context.Background() nothing ever cancelled,
so the loop only ended early on a driver error. Adding real deadlines made
the path reachable, so the check belongs in the same change.

Also corrects the requestTimeout comment. It described the constant as
bounding a request, but routes that run the existence middleware before
the handler make two independent calls and can wait up to twice as long.
It bounds one data layer call.
Copilot AI review requested due to automatic review settings August 1, 2026 12:27
…ately

Raised by Copilot on review. In Fiber middleware `return c.Next()` runs
the whole downstream chain before the middleware itself returns, so a
deferred cancel() only fires at the very end. The context is used for one
repository lookup, but its timer stayed armed for the entire request.

Calling cancel() directly after the lookup releases it as soon as it is no
longer needed. Safe here because GetCity and GetUser scan the row into the
struct before returning, so nothing lazily depends on the context
afterwards, and placing the call before the error branches covers every
return path.
Copilot AI dismissed their stale review, a newer Copilot review was requested August 1, 2026 12:29
Copilot AI previously approved these changes Aug 1, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Ready to approve

The changes consistently propagate request cancellation and add per-operation deadlines without introducing API breaks, and the added Rows.Err() handling correctly avoids partial-success returns on cancellation.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details
  • Files reviewed: 6/6 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Copilot AI review requested due to automatic review settings August 1, 2026 12:29
Copilot AI dismissed their stale review, a newer Copilot review was requested August 1, 2026 12:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Ready to approve

The changes consistently propagate request-scoped contexts with timeouts and add correct rows.Err() handling without introducing API or behavioral inconsistencies in the touched recipe paths.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details
  • Files reviewed: 6/6 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

@ReneWerner87
ReneWerner87 merged commit 045b562 into master Aug 1, 2026
10 checks passed
@ReneWerner87
ReneWerner87 deleted the claude/mariadb-request-context branch August 1, 2026 12:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update MariaDB recipe for Timeout

3 participants