-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Description
Description
The context.Context fulfils 3 different purposes:
- bag of values
- deadline
- cancellation.
These different functionalities are not apparent in any API - one has to rely on documentation or read the source code to find out which of the different functionalities is expeceted from the user of any specific API.
I proppose that we take a leaf out of the io.Reader, io.ReadWriter ... interfaces in the io package and define:
- context.Canceller
- context.Values
- context.Deadline
- context.DeadLineCanceller
- context.ValuesCanceller
- context.ValuesDeadline
- context.Context - all of them for backwards compatibility
API authors can then specify the correct context and this will document in the code the expected context behaviour.
Cons:
- Some packages will parse the context and act accordingly and this scheme will not work for them without some modification. For example the azure-sdk-for-go will enact a Timeout if the passed in context has a Timeout attribute - otherwise it reverts to an internal retry with backoff.
- adopting this for any API will probably cause a major version change.
From experience
Coding guidelines can dictate that a context contain values for general use such as headers or grpc metadayta. This leads to the decision to mandate that every network call uses a common context without realising that this common context might also contain a deadline which on every call becomes shorter and shorter leading to general flakiness. Fixing this in a large codebase without knowing what is expected of any passed in context is not trivial perhaps.
Hence the recent introduction of context.WithoutCancel().
I would assert that if we had the above subcontexts then WithoutCaancel may not be required.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
Activity
[-]proposal: affected/package: context: functional interfaces[/-][+]proposal: context: functional interfaces[/+]apparentlymart commentedon Aug 14, 2023
Hi @eccles,
The
context.Context
mechanism's primary mission is to allow cross-cutting concerns to travel across API boundaries without the entire application needing to agree on what those cross-cutting concerns are.For example, in my own application I might have decided to use a particular distributed tracing instrumentation API, but it's unlikely that third-party libraries I'm using will have made the same decision. If I'm using a function in that third-party library to indirectly call a function in my own application -- a typical example being stdlib
net/http.Server
/Client
calling my own application'shttp.Handler
orhttptrace.ClientTrace
-- I cannot modifynet/http
's API to specify that it should expect and pass downstream acontext.Values
specifically.With that said, I feel unsure about how the more specific interfaces you described here would be used. You say "API authors can then specify the correct context", but you've not described how the API author would decide which type to use.
If you are imagining using this only for calls between functions in a single codebase then indeed for that case I could imagine how that might work, but that situation is not the scenario that the
context
package API is intended for.Of course that doesn't mean that the scope of
context
couldn't grow to better support that situation, but if that is your intention then I'd suggest including some concrete examples of how you'd use this in real code so that the value proposition is easier to see.ianlancetaylor commentedon Aug 14, 2023
CC @Sajmani
eccles commentedon Aug 15, 2023
Thank you @apparentlymart for your comments.
I am no proposing that we get rid of the generic context.Context. Just simply making it clearer for any particular API on how that AP is expected to be used with regards to the required context.Context argument.
So for example calling a listener of some kind (httpserver or similar):
which indicates that this function could be cancelled
or
which indicates that a timeout should be specified in the context and the Values will be used (maybe in the headers...)
or
which indicates that only a deadline will be expected in the context.
eccles commentedon Jun 25, 2024
Just for emphasis this proposal simply aims to make the intent of the API of any package clearer.
neild commentedon Jun 26, 2024
The advantage of context.Context is that we have a single type used across the ecosystem to carry cross-cutting concerns across API boundaries. There are various unfortunate aspects to how Contexts are defined, but they are still widely used because a single, common type outweighs the negatives. Splitting Context into a variety of types would undo that advantage.
eccles commentedon Aug 14, 2024
@neild Thanks for your comment but my experience in trying to figure out how a generic context argument is intended to be used and having to resort to reading the many layers of code involved in the third party package contradicts. I see context.context as some form of God object whose intended use is unclear.
We have precedent in the way io.Reader and its related interfaces are constructed and this seems to be a good pattern.
seankhliao commentedon May 11, 2025
I don't think this is a direction we want to go in.