DEV Community

Israel Parra
Israel Parra

Posted on

Golang context

Golang context

The official documentation mention provides the following description:

“Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.”

In other words, the context helps us to define scopes in our different processes and control when each one needs to be completed or terminated according to the parent process results.

One common example of the use of context is when we are working with APIs, then we define (or the used framework) the parent context that should be shared along the request process. In that kind of context, we have all the information related to the request one good example is the *gin-gonic* framework, where its developers make very good use of the context along with the requests.

Another example is the use of goroutines, in that case, we could implement the context and some of its main functions to ensure to termination of the subprocess and reduce resource costs.

Contexts are particularly useful in situations where you need to perform multiple operations concurrently and you want centralized control over their execution. For example, contexts can be used to:

  • Set deadlines for trades and cancel them if they take too long.

  • Propagate shared values, such as authentication or configuration information.

  • Provide abort signals to goroutines and functions that use the context.

  • Provide diagnostic information such as traces and logs.

In Golang is an important tool for concurrent programming and helps us provide additional information through function calls and goroutines safely and efficiently.

Context TODO

“Code should use context.TODO when it’s unclear which Context to use or it is not yet available (because the surrounding function has not yet been extended to accept a Context parameter)”.

Context Background

“context.Background returns a non-nil, empty Context. It is never canceled, has no values, and has no deadline. It is typically used by the main function, initialization, and tests, and as the top-level Context for incoming requests”.

Context Functions

In this section, I will show you some of the most used context functions context.WithCancel and context.WitTimeout , both are similar, helping us to close the subprocess from the parent context.

WithCancel

context.WithCancel() is a function in Golang that is used to create a new context from a parent context and a cancel function that is used to cancel the child context and all its related goroutines.

The context.WithCancel() function takes a parent context as an argument and returns two values: a child context and a cancel function. The child context is a new context that is derived from the parent context and includes additional information such as a cancellation signal. The cancel function is used to cancel the child context and all related goroutines.

Here is one example:

package main

import (
 "context"
 "fmt"
)

func main() {
 // gen generates integers in a separate goroutine and
 // sends them to the returned channel.
 // The callers of gen need to cancel the context once
 // they are done consuming generated integers not to leak
 // the internal goroutine started by gen.
 gen := func(ctx context.Context) <-chan int {
    dst := make(chan int)
    n := 1
    go func() {
       for {
          select {
            case <-ctx.Done():
               return // returning not to leak the goroutine
            case dst <- n:
               n++
          }
       }
    }()
    return dst
 }

 ctx, cancel := context.WithCancel(context.Background())
 defer cancel() // cancel when we are finished consuming integers

 for n := range gen(ctx) {
    fmt.Println(n)
    if n == 5 {
       break
    }
 }
}
Enter fullscreen mode Exit fullscreen mode

WithTimeout

context.WithTimeout() is a function in Golang that is used to create a new context from a parent context with a timeout duration. The timeout duration specifies how long the context and all its related goroutines should wait before canceling automatically.

The context.WithTimeout() function takes a parent context and a timeout duration as arguments and returns two values: a child context and a cancel function. The child context is a new context that is derived from the parent context and includes additional information such as a deadline for canceling the context. The cancel function is used to cancel the child context and all related goroutines.

Here is one example:

package main

import (
 "context"
 "fmt"
 "time"
)

const shortDuration = 1 * time.Millisecond

func main() {
   // Pass a context with a timeout to tell a blocking function that it
   // should abandon its work after the timeout elapses.
   ctx, cancel := context.WithTimeout(context.Background(), shortDuration)
   defer cancel()

   select {
     case <-time.After(1 * time.Second):
        fmt.Println("overslept")
     case <-ctx.Done():
        fmt.Println(ctx.Err()) // prints "context deadline exceeded"
   }

}
Enter fullscreen mode Exit fullscreen mode

output:

context deadline exceeded
Enter fullscreen mode Exit fullscreen mode

Another example:

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    // Create a parent context using `context.Background()`
    ctx := context.Background()

    // Create a child context with a timeout of 2 seconds using `context.WithTimeout()`
    ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
    defer cancel()

    // Simulate a long-running task that takes 3 seconds to complete
    go longRunningTask(ctx)

    // Wait for the child context to be canceled or to timeout
    select {
    case <-ctx.Done():
        fmt.Println(ctx.Err())
    case <-time.After(3 * time.Second):
        fmt.Println("Task took too long to complete")
    }

    fmt.Println("Done.")
}

func longRunningTask(ctx context.Context) {
    fmt.Println("Task started.")

    // Simulate a task that takes 3 seconds to complete
    select {
    case <-time.After(3 * time.Second):
        fmt.Println("Task completed.")
    case <-ctx.Done():
        fmt.Println(ctx.Err())
    }
}
Enter fullscreen mode Exit fullscreen mode

output:

Task started.
context deadline exceeded
Done.

Program exited.
Enter fullscreen mode Exit fullscreen mode

Conclusion

In conclusion, the Golang context package provides a powerful mechanism for managing and communicating between goroutines. Allowing you to manage deadlines, cancellations and request scope values across API boundaries and between processes.

By using the context package, you can write concurrent code that is efficient, safe, and easy to reason with.

Provides a standardized way to propagate request-scoped values, such as authentication tokens or tracking information, across multiple API functions and boundaries.

It allows you to manage the lifetime of goroutines in a clean and consistent way, making it easy to prevent resource leaks and manage system resources efficiently.

Overall, the context pack is an essential part of writing scalable, robust, and efficient concurrent applications in Golang.

Information is taken from the official web seite https://pkg.go.dev/context

Top comments (0)