Skip to content

add a thread safe context that can be used downstream and mutated#4172

Open
rubensayshi wants to merge 1 commit intogin-gonic:masterfrom
prvbl:internal-ctx
Open

add a thread safe context that can be used downstream and mutated#4172
rubensayshi wants to merge 1 commit intogin-gonic:masterfrom
prvbl:internal-ctx

Conversation

@rubensayshi
Copy link

@rubensayshi rubensayshi commented Mar 3, 2025

It's currently unsafe to use c.Request.Context from the *gin.Context to pass to downstream functions AND do any mutations to the c.Request.Context.
Even when you do c.Request = c.Request.WithContext(...) you'll end up with the go race detector flagging the unsafe reading of the c.Request and writing to c.Request.

And even when you're not really doing anything .WithContext there's a chance that the context pool causes the race detector to get angry

However it would be really nice to be able to put values into the *gin.Context with context.WithValue() in a thread-safe way that allows downstream usage of *gin.Context as context.Context to access those values.
For example, an auth middleware adding some debugging /loggin related values with context.WithValue() will not be lost along the way, or adding a otel.Tracer to the context with additional options etc.

Making all the places where gin touches c.Request thread-safe with a lock would be a significant undertaking and would have an impact on performance (probably talking about nano seconds, but still non zero impact).

With the MR we're adding a thread-safe way to carry around and mutate a context.Context inside *gin.Context without having to protect c.Request.

In practice the c.Request.Context isn't going to be very interesting to wrap anyway, so loosing that as the "root" context probably isn't a issue for anyone.
It's trivial to make the root InternalContext the c.Request.Context when we do .reset() (if ContextWithFallback is enabled), but I wanted to keep this MR as small as possible.
And it would have one quirky downside that if someone uses UseInternalContext and does something like c.Request = c.Request.WithContext(...) then it wouldn't have any effect.

There's a couple of mentions of issues around this before:

@rubensayshi rubensayshi changed the title add a thread safe context that can be used add a thread safe context that can be used downstream and mutated Mar 4, 2025
@appleboy
Copy link
Member

appleboy commented Mar 23, 2025

@rubensayshi Please update the PR to the latest source code for the CI/CD flow.

@codecov
Copy link

codecov bot commented Apr 14, 2025

Codecov Report

❌ Patch coverage is 77.77778% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.70%. Comparing base (3dc1cd6) to head (4218569).
⚠️ Report is 202 commits behind head on master.

Files with missing lines Patch % Lines
context.go 75.75% 7 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4172      +/-   ##
==========================================
- Coverage   99.21%   98.70%   -0.51%     
==========================================
  Files          42       44       +2     
  Lines        3182     2937     -245     
==========================================
- Hits         3157     2899     -258     
- Misses         17       26       +9     
- Partials        8       12       +4     
Flag Coverage Δ
?
--ldflags="-checklinkname=0" -tags sonic 98.69% <77.77%> (?)
-tags go_json 98.62% <77.77%> (?)
-tags nomsgpack 98.68% <77.77%> (?)
go-1.18 ?
go-1.19 ?
go-1.20 ?
go-1.21 ?
go-1.24 98.70% <77.77%> (?)
go-1.25 98.70% <77.77%> (?)
macos-latest 98.70% <77.77%> (-0.51%) ⬇️
ubuntu-latest 98.70% <77.77%> (-0.51%) ⬇️

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.

@rubensayshi
Copy link
Author

happy to increase the coverage if there's an actual chance this would get merged! :D

@RemiBou
Copy link

RemiBou commented Jul 18, 2025

can we get someone to look into it ? it's failing many of our concurrency tests because of the race condition

@appleboy
Copy link
Member

I will take a look.

@appleboy appleboy requested a review from Copilot July 19, 2025 06:57
@appleboy appleboy added this to the v1.12 milestone Jul 19, 2025
Copy link
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 introduces thread-safe context management capabilities to Gin by adding an internal context mechanism that allows safe mutations without race conditions on c.Request.Context(). The implementation addresses known race detection issues when using context values in concurrent scenarios.

  • Adds UseInternalContext feature flag to enable thread-safe internal context management
  • Implements WithInternalContext() and InternalContext() methods with proper mutex protection
  • Modifies existing context methods to support internal context fallback when enabled

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
context.go Core implementation of thread-safe internal context with mutex protection and context interface methods
gin.go Adds UseInternalContext configuration flag and updates comment formatting
context_test.go Comprehensive test coverage for all internal context methods and edge cases
test_helpers.go Enhances CreateTestContext with optional configuration functions for testing
Comments suppressed due to low confidence (1)

context.go:1357

  • [nitpick] The function name useInternalContext is ambiguous - it reads like an action rather than a predicate. Consider renaming to hasInternalContext or isInternalContextEnabled to better indicate it's a boolean check.
func (c *Context) useInternalContext() bool {

@rubensayshi
Copy link
Author

@appleboy any chance that we can pick this up again?

seems like with go1.25 either the race detector go more aggressive or things just got more optimized that the race is more easily detectable...
either way using gin.Context as a context being fed downstream has gotten trickier and we're actually having a race with initContextClose from database/sql, fairly commonly used I'd say.

@rubensayshi
Copy link
Author

@appleboy sorry for pinging again, but I'd be happy to put in the effort to polish this MR if neccesary!

@appleboy
Copy link
Member

appleboy commented Oct 7, 2025

image

@rubensayshi, please help update the PR to the master branch.

@rubensayshi
Copy link
Author

@appleboy sorry, did the rebase now.

I don't see the pipeline running anymore for the MR 🤔 ?

@rubensayshi
Copy link
Author

hmm after some testing we realized this no longer propagates the ctx.Err() when the http request is canceled by the client...

@appleboy appleboy modified the milestones: v1.12, v1.x Feb 28, 2026
@appleboy
Copy link
Member

move to next milestone

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants