Documentation
¶
Overview ¶
Package implements a graceful shutdown context tree for your goroutines.
It means that parent context wouldn't close until all its children's worked.
example: ¶
You are creating a context tree:
root => child1 => child2 => child3
and trying to close the root.
All subchilds will close in reverse order (first - child3, then child2, child1, root). This closing order is absolutely essential because the child context could use some parent resources or send some signals to the parent. If a parent closes before the child, it will cause undefined behavior or goroutine locking.
Unfortunately, context from the standard Go library does not guarantee this closing order. See issue: https://github.com/golang/go/issues/51075
This module resolves this problem and guarantees a correct closing order.
Example ¶
package main import ( "fmt" "time" context "github.com/mcfly722/context" ) type node struct { name string } func newNode(name string) *node { return &node{name: name} } func (node *node) getName() string { return node.name } // this method node should implement as Goroutine loop func (node *node) Go(current context.Context) { loop: for { select { case _, isOpened := <-current.Context(): // this method returns context channel. If it closes, it means that we need to finish select loop if !isOpened { break loop } default: // you can use default or not, it works in both cases { } } } fmt.Printf("4. context '%v' closed\n", node.getName()) } func main() { rootContext := context.NewRootContext(newNode("root")) child1Context, _ := rootContext.NewContextFor(newNode("child1")) child2Context, _ := child1Context.NewContextFor(newNode("child2")) child2Context.NewContextFor(newNode("child3")) fmt.Printf("1. now waiting for 1 sec...\n") go func() { time.Sleep(1 * time.Second) fmt.Printf("3. one second pass\n") rootContext.Close() }() rootContext.Wait() fmt.Printf("5. end\n") }
Output: 1. now waiting for 1 sec... 3. one second pass 4. context 'child3' closed 4. context 'child2' closed 4. context 'child1' closed 4. context 'root' closed 5. end
Index ¶
Examples ¶
Constants ¶
const ExitFromContextWithoutClosePanic customPanic = "Exit from Context Without Close() method"
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ChildContext ¶ added in v1.0.2
type ChildContext interface { // create a new child context, for instance, what implements the instance interface NewContextFor(instance ContextedInstance) (ChildContext, error) // Close current context Close() }
ChildContext obtained from the [NewContextFor] function.
Any child could have several subchilds.
During closing, this child would be a parent for all its sub-childs.
type ClosingIsInProcessForDisposingError ¶ added in v1.0.6
type ClosingIsInProcessForDisposingError struct{}
func (*ClosingIsInProcessForDisposingError) Error ¶ added in v1.0.6
func (err *ClosingIsInProcessForDisposingError) Error() string
type ClosingIsInProcessForFreezeError ¶ added in v1.0.6
type ClosingIsInProcessForFreezeError struct{}
func (*ClosingIsInProcessForFreezeError) Error ¶ added in v1.0.6
func (err *ClosingIsInProcessForFreezeError) Error() string
type Context ¶
type Context interface { // creates a new child context, for instance, what implements ContextedInstance interface NewContextFor(instance ContextedInstance) (ChildContext, error) // When this channel closes, it means that the child context should exit from the Go function. Context() chan struct{} // Close the current context and all children in reverse order. Close() }
Instances of this interface are sent to your node through the Go() method.
(see ContextedInstance)
type ContextedInstance ¶
type ContextedInstance interface {
Go(current Context)
}
This interface should be implemented by your nodes.
The module automatically starts Go(...) method with the current Context and automatically waits until it ends. You could not exit from this method without context closing (otherwise ExitFromContextWithoutClosePanic occurs).
Example:
type node struct {} func (node *node) Go(current context.Context) { loop: for { select { case _, isOpened := <-current.Context(): if !isOpened { break loop } } } }
type RootContext ¶
type RootContext interface { // Creates new Context from your instance what implements [ContextedInstance] interface. // If current root context is already in closing state it returns [ClosingIsInProcessForFreezeError] or [ClosingIsInProcessForDisposingError] NewContextFor(instance ContextedInstance) (ChildContext, error) // Waits till current root context would be Closeed. Wait() // Close current root context and all childs according reverse order. Close() }
The RootContext interface is returned by the NewRootContext function.
func NewRootContext ¶
func NewRootContext(instance ContextedInstance) RootContext
NewRootContext function generates and starts new root context