Skip to content

Commit 96ad5ac

Browse files
authored
Add "A Note on Concurrency" (#272)
* Add "A Note on Concurrency" * Improve articulation of the problem and remove examples * Update "A Note on Concurrency"
1 parent 436cd65 commit 96ad5ac

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

website/content/guide/context.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,44 @@ e.GET("/", func(c echo.Context) error {
5454
return cc.String(200, "OK")
5555
})
5656
```
57+
58+
## A Note on Concurrency
59+
60+
`Context` must not be accessed out of the goroutine handling the request. There are two reasons:
61+
62+
1. `Context` has functions that are dangerous to execute from multiple goroutines. Therefore, only one goroutine should access it.
63+
2. Echo uses a pool to create `Context`'s. When the request handling finishes, Echo returns the `Context` to the pool.
64+
65+
See issue [1908](https://github.com/labstack/echo/issues/1908) for a "cautionary tale" caused by this reason. Concurrency is complicated. Beware of this pitfall when working with goroutines.
66+
67+
### Solutions
68+
69+
#### Use a channel
70+
71+
A better design might be to use a channel:
72+
73+
```go
74+
func(c echo.Context) error {
75+
ca := make(chan string, 1) // To prevent this channel from blocking, size is set to 1.
76+
r := c.Request()
77+
method := r.Method
78+
79+
go func() {
80+
// This function must not touch the Context.
81+
82+
fmt.Printf("Method: %s\n", method)
83+
84+
// Do some long running operations...
85+
86+
ca <- "Hey!"
87+
}()
88+
89+
select {
90+
case result := <-ca:
91+
return c.String(http.StatusOK, "Result: "+result)
92+
case <-c.Request().Context().Done(): // Check context.
93+
// If it reaches here, this means that context was canceled (a timeout was reached, etc.).
94+
return nil
95+
}
96+
}
97+
```

0 commit comments

Comments
 (0)