-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
105 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package context | ||
|
||
import "context" | ||
|
||
// valueOnlyContext provides a utility to preserve only the values of a | ||
// Context. Suppressing any cancellation or deadline on that context being | ||
// propagated downstream of this value. | ||
// | ||
// If preserveExpiredValues is false (default), and the valueCtx is canceled, | ||
// calls to lookup values with the Values method, will always return nil. Setting | ||
// preserveExpiredValues to true, will allow the valueOnlyContext to lookup | ||
// values in valueCtx even if valueCtx is canceled. | ||
// | ||
// Based on the Go standard libraries net/lookup.go onlyValuesCtx utility. | ||
// https://github.com/golang/go/blob/da2773fe3e2f6106634673a38dc3a6eb875fe7d8/src/net/lookup.go | ||
type valueOnlyContext struct { | ||
context.Context | ||
|
||
preserveExpiredValues bool | ||
valuesCtx context.Context | ||
} | ||
|
||
var _ context.Context = (*valueOnlyContext)(nil) | ||
|
||
// Value looks up the key, returning its value. If configured to not preserve | ||
// values of expired context, and the wrapping context is canceled, nil will be | ||
// returned. | ||
func (v *valueOnlyContext) Value(key interface{}) interface{} { | ||
if !v.preserveExpiredValues { | ||
select { | ||
case <-v.valuesCtx.Done(): | ||
return nil | ||
default: | ||
} | ||
} | ||
|
||
return v.valuesCtx.Value(key) | ||
} | ||
|
||
// WithSuppressCancel wraps the Context value, suppressing its deadline and | ||
// cancellation events being propagated downstream to consumer of the returned | ||
// context. | ||
// | ||
// By default the wrapped Context's Values are available downstream until the | ||
// wrapped Context is canceled. Once the wrapped Context is canceled, Values | ||
// method called on the context return will no longer lookup any key. As they | ||
// are now considered expired. | ||
// | ||
// To override this behavior, use WithPreserveExpiredValues on the Context | ||
// before it is wrapped by WithSuppressCancel. This will make the Context | ||
// returned by WithSuppressCancel allow lookup of expired values. | ||
func WithSuppressCancel(ctx context.Context) context.Context { | ||
return &valueOnlyContext{ | ||
Context: context.Background(), | ||
valuesCtx: ctx, | ||
|
||
preserveExpiredValues: GetPreserveExpiredValues(ctx), | ||
} | ||
} | ||
|
||
type preserveExpiredValuesKey struct{} | ||
|
||
// WithPreserveExpiredValues adds a Value to the Context if expired values | ||
// should be preserved, and looked up by a Context wrapped by | ||
// WithSuppressCancel. | ||
// | ||
// WithPreserveExpiredValues must be added as a value to a Context, before that | ||
// Context is wrapped by WithSuppressCancel | ||
func WithPreserveExpiredValues(ctx context.Context, enable bool) context.Context { | ||
return context.WithValue(ctx, preserveExpiredValuesKey{}, enable) | ||
} | ||
|
||
// GetPreserveExpiredValues looks up, and returns the PreserveExpressValues | ||
// value in the context. Returning true if enabled, false otherwise. | ||
func GetPreserveExpiredValues(ctx context.Context) bool { | ||
v := ctx.Value(preserveExpiredValuesKey{}) | ||
if v != nil { | ||
return v.(bool) | ||
} | ||
return false | ||
} |