constext

package module
v0.0.0-...-836a144 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 21, 2017 License: MIT Imports: 3 Imported by: 96

README

constext Doc Status

constext allows you to cons Contexts together as a pair, conjoining them for the purpose of all Context behaviors:

  1. If either parent context is canceled, the constext is canceled. The err is set to whatever the err of the parent that was canceled.
  2. If either parent has a deadline, the constext uses that same deadline. If both have a deadline, it uses the sooner/lesser one.
  3. Values from both parents are unioned together. When a key is present in both parent trees, the left (first) context supercedes the right (second).

Paired contexts can be recombined using the standard context.With*() functions.

Usage

Use is simple, and patterned after the context package. The constext.Cons() function takes two context.Context arguments and returns a single, unified one, along with a context.CancelFunc.

cctx, cancelFunc := constext.Cons(context.Background(), context.Background())

True to the spirit of cons, recursive trees can be formed through nesting:

bg := context.Background()
cctx := constext.Cons(bg, constext.Cons(bg, constext.Cons(bg, bg)))

This probably isn't a good idea, but it's possible.

Rationale

While the unary model of context works well for the original vision - an object operating within an [HTTP] request's scope - there are times when we need a little more.

For example: in dep, the subsystem that manages interaction with source repositories is called a SourceManager. It is a long-lived object; generally, only one is created over the course of any single dep invocation. The SourceManager has a number of methods on it that may initiate network and/or disk interaction. As such, these methods need to take a context.Context, so that the caller can cancel them if needed.

However, this is not sufficient. The SourceManager itself may need to be terminated (e.g., if the process received a signal). In such a case, in-flight method calls also need to be canceled, to avoid leaving disk in inconsistent state.

As a result, each in-flight request serves two parents - the initator of the request, and the SourceManager itself. We can abstract away this complexity by having a Context for each, and Consing them together on a per-call basis.

Caveats

tl;dr: GC doesn't work right, so explicitly cancel constexts when done with them.

The stdlib context packages uses internal tree-walking trickery to avoid spawning goroutines unless it actually has to. We can't rely on that same trickery, in part because we can't access the tree internals, but also because it's not so straightforward when multiple parents are involved. Consequently, Cons() almost always must spawn a goroutine to ensure correct cancellation behavior, whereas e.g. context.WithCancel() rarely has to.

If, as in the use case above, your constext has one short-lived and one long-lived parent, and the short-lived parent is not explicitly canceled (which is typical), then until the long-lived parent is canceled, neither the constext, nor any otherwise-unreachable members of the short-lived context tree will be GCed.

So, for now, explicitly cancel your constexts before they go out of scope, otherwise you'll leak memory.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Cons

Cons takes two Contexts and combines them into a pair, conjoining their behavior:

  • If either parent context is canceled, the constext is canceled. The err is set to whatever the err of the parent that was canceled.
  • If either parent has a deadline, the constext uses that same deadline. If both have a deadline, it uses the sooner/lesser one.
  • Values from both parents are unioned together. When a key is present in both parent trees, the left (first) context supercedes the right (second).

All the normal context.With*() funcs should incorporate constexts correctly.

If the two parent contexts both return a nil channel from Done() (which can occur if both parents are Background, or were created only through context.WithValue()), then the returned cancelFunc() is a no-op; calling it will NOT result in the termination of any sub-contexts later created.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL