Go Contexts
What is Context in Go?
Context in Go helps us manage how long a function should run. It is useful when we want to cancel operations, set time limits, or pass values across different parts of a program.
Creating a Simple Context
We can create a basic context using context.Background()
. This is like a starting point for any context-based operation.
package main
import (
"context"
"fmt"
)
func main() {
ctx := context.Background()
fmt.Println("Context created:", ctx)
}
This code creates an empty context that can be used as a base for more complex operations.
How to Cancel a Running Operation
Sometimes, we want to stop a function after a certain condition. For example, if a request is taking too long, we might want to cancel it. This is where context.WithCancel()
is useful.
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
go func() {
time.Sleep(2 * time.Second)
cancel() // Stop the operation after 2 seconds
}()
<-ctx.Done()
fmt.Println("Operation stopped:", ctx.Err())
}
Here, we create a context that can be canceled. After 2 seconds, the function is stopped using cancel()
.
Setting a Time Limit
We can also set a time limit so that a function stops automatically after a certain period. This is useful for network calls or database queries.
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() // Always cancel to free resources
select {
case <-time.After(5 * time.Second):
fmt.Println("Completed")
case <-ctx.Done():
fmt.Println("Timeout reached:", ctx.Err())
}
}
If the operation takes longer than 3 seconds, the context cancels it and prints a timeout message.
Using Deadlines
Sometimes, we need a function to stop at a specific time instead of after a fixed duration. This is done using context.WithDeadline()
.
package main
import (
"context"
"fmt"
"time"
)
func main() {
deadline := time.Now().Add(2 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()
select {
case <-time.After(3 * time.Second):
fmt.Println("Operation completed")
case <-ctx.Done():
fmt.Println("Deadline reached:", ctx.Err())
}
}
This ensures that the function does not run beyond the deadline.
Passing Data in Context
We can use context.WithValue()
to pass key-value pairs in a context. This is helpful for sharing small bits of data across different parts of a program.
package main
import (
"context"
"fmt"
)
func main() {
ctx := context.WithValue(context.Background(), "username", "Mahendra")
process(ctx)
}
func process(ctx context.Context) {
user := ctx.Value("username").(string)
fmt.Println("User:", user)
}
Here, we pass a username through the context and retrieve it in another function.
Why Use Context?
- ✅ Helps stop operations when needed (like canceling a slow API call).
- ✅ Saves memory by preventing goroutines from running forever.
- ✅ Allows passing useful data across functions.
Conclusion
The context
package makes Go programs more efficient and reliable. It helps manage timeouts, cancellations, and shared data.
Next, we will explore Building HTTP Servers in Go!