forked from jackyzha0/quartz
-
Notifications
You must be signed in to change notification settings - Fork 1
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
1 changed file
with
147 additions
and
0 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
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.# |