Skip to content

Commit

Permalink
Add golang context
Browse files Browse the repository at this point in the history
  • Loading branch information
shubh2294 committed Oct 9, 2024
1 parent fecae45 commit 502dd21
Showing 1 changed file with 147 additions and 0 deletions.
147 changes: 147 additions & 0 deletions content/SoftwareEngineering/Golang context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#context #golang

In Go (Golang), the `context` package provides a way to carry deadlines, cancellation signals, and request-scoped values across API boundaries and between goroutines. It is widely used for managing the lifecycle of requests, controlling execution flow, and passing metadata or configuration between different parts of an application.

### Core Concept of `context`
A `context.Context` is an interface that provides a way to:
1. **Pass Metadata**: Store and retrieve values specific to the request or function.
2. **Handle Deadlines**: Set and enforce deadlines for operations.
3. **Cancel Operations**: Cancel ongoing operations when a request is no longer needed or a timeout occurs.
4. **Propagate Cancellation**: Automatically propagate cancellation to all goroutines derived from a parent `Context`.

### Why Use `context`?
The context is mainly used in scenarios where multiple goroutines need to coordinate execution or exit early when something goes wrong. This is especially important in concurrent systems where handling cancellations and timeouts effectively can prevent resource leaks and improve performance.

### How Context Works
A `context.Context` is immutable and is used to create derived contexts that inherit values, deadlines, and cancellation signals. This means that contexts are passed down the call stack, but any modifications (e.g., adding a deadline or value) result in a new context.

### Types of Contexts
The `context` package provides several types of contexts:

1. **`context.Background()`**: The root context, often used as a starting point for deriving other contexts. Typically used in main functions, initializations, or when no other context is available.

2. **`context.TODO()`**: Similar to `context.Background()`, but used as a placeholder when the context is not yet defined or planned to be implemented later.

3. **`context.WithCancel(parent Context)`**: Creates a new context that can be cancelled manually. It returns a derived context and a `cancel` function that should be called to release resources once the operation is complete.

4. **`context.WithTimeout(parent Context, timeout time.Duration)`**: Creates a new context that automatically cancels itself after the specified duration. Useful for setting timeouts on operations like API calls or database queries.

5. **`context.WithDeadline(parent Context, deadline time.Time)`**: Creates a context that automatically cancels at a specified point in time.

6. **`context.WithValue(parent Context, key, value interface{})`**: Creates a new context that carries key-value pairs. This is commonly used for passing request-scoped values like user IDs, authentication tokens, or logging information.

### Context Functions
The `context.Context` interface has four key methods:

1. **`Done()`**: Returns a channel that is closed when the context is cancelled or reaches its deadline. Use this to detect cancellation.

2. **`Err()`**: Returns an error indicating why the context was cancelled (`context.Canceled` or `context.DeadlineExceeded`).

3. **`Deadline()`**: Returns the time when the context will be cancelled, if any.

4. **`Value(key interface{})`**: Retrieves a value associated with the context. Typically used sparingly to pass request-scoped values.

### Usage Examples

#### Example 1: Using `context.WithCancel`

```go
package main

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

func main() {
ctx, cancel := context.WithCancel(context.Background())

go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("Goroutine: Received cancellation signal. Exiting.")
return
default:
fmt.Println("Goroutine: Doing some work...")
time.Sleep(500 * time.Millisecond)
}
}
}(ctx)

time.Sleep(2 * time.Second) // Simulate some processing time
fmt.Println("Main: Sending cancellation signal.")
cancel() // Cancel the context

time.Sleep(1 * time.Second) // Give some time for the goroutine to exit
fmt.Println("Main: Exiting.")
}
```

In this example, the main goroutine creates a cancellable context and launches another goroutine that does some work. When the main goroutine calls `cancel()`, the other goroutine detects this and exits gracefully.

#### Example 2: Using `context.WithTimeout`

```go
package main

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

func main() {
// Create a context that will timeout after 3 seconds
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() // Ensure resources are cleaned up

select {
case <-time.After(5 * time.Second):
fmt.Println("Operation completed without timeout.")
case <-ctx.Done():
fmt.Println("Operation timed out:", ctx.Err())
}
}
```

In this example, a context with a 3-second timeout is created. The `select` statement waits for either the operation to complete or the context to timeout. Since the `time.After` call takes 5 seconds, the context will timeout first, printing the timeout message.

#### Example 3: Passing Values Using Context

```go
package main

import (
"context"
"fmt"
)

func main() {
ctx := context.WithValue(context.Background(), "userID", 1234)

processRequest(ctx)
}

func processRequest(ctx context.Context) {
userID := ctx.Value("userID")
if userID != nil {
fmt.Println("Processing request for user ID:", userID)
} else {
fmt.Println("No user ID found in context.")
}
}
```

In this example, a value is stored in the context (`userID`) and passed down to the `processRequest` function, which retrieves and uses it.

### Best Practices

1. **Don’t Pass Contexts in Structs**: Always pass contexts as the first parameter to functions.
2. **Keep Contexts Immutable**: Never modify a context directly. Always use context constructors (`WithCancel`, `WithTimeout`, etc.) to create derived contexts.
3. **Avoid Using Context for Optional Parameters**: Use context values sparingly and only for request-scoped data.
4. **Cancel Contexts When No Longer Needed**: Always call the `cancel` function when using `WithCancel`, `WithTimeout`, or `WithDeadline` to avoid resource leaks.

### Summary
The Go `context` package is essential for managing request lifecycles, handling cancellations, and propagating deadlines across goroutines. It is especially useful for building reliable, concurrent applications that need to respect deadlines and handle cancellations gracefully.#

0 comments on commit 502dd21

Please sign in to comment.