-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to clone echo context? #1633
Comments
|
@vishr @lammel could you please take a look at this? func extractionMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
cc := c.Echo().AcquireContext()
cc.Reset(c.Request().Clone(context.Background()), c.Response().Writer)
cc.SetPath(c.Path())
cc.SetParamNames(c.ParamNames()...)
cc.SetParamValues(c.ParamValues()...)
cc.SetHandler(c.Handler())
cc.Set("myAuthData", createAuthData(cc))
go func() {
defer server.ReleaseContext(cc)
_ = next(cc)
}()
return c.String(http.StatusOK, "Accepted")
}
}After I did this I started getting panics in service It looks like empty pvalue list seems to be coming here Am I misunderstanding something here? |
|
Hi @kunal-sanghvi, I guess you are facing an issue that was fixed in a later version than 3.3.10 Besides of that, I think that the correct approach is the one that you showed in your second comment. For all the cases, Echo uses a sync.Pool to manage Context instances. In your first example, the Context could get reused/reset by other request during the use of it in your goroutine. If you make use of Echo#AcquireContext and Echo#ReleaseContext, you still will get Context instances from the same sync.Pool, but you will decide when to put it there again to be reused later (that is done on Echo#ReleaseContext) |
|
Hi @pafuent, we indeed felt the second comment approach would work but instead during peak load times we started seeing panics in our service But now I'd once try to update to v4.1.17 and check for the same |
|
@kunal-sanghvi Did you had the opportunity to check if v4.1.17 solved your issue? |
|
You should not pass echo context to other goroutines. Echo context instances are borrowed at the start of serving request and put pack to pool at the end of the request. If you pass it to different goroutine (with different lifetime) you have data race. For asynchronous endpoints it is cleaner architecture when you extract needed data from request in handler method and use that extracted data to start async process (goroutine) and after starting return httpstatus from handler. In that case you can do some basic input validation and send errors to requester. architecturally you should not mix transport layer (echo.Context) with you business layer (async process) |
|
@aldas while that would likely be Ideal, there is a LOT of important information stored in context. I have a number of async tasks that start after a user hits any number of endpoints, and one of the things that I do is use the context for Logging in those tasks. It allows me to track and log the User and other relevant information even after the main request is done (theoretically). The issue is that the logging that I am doing is handled by a central library to keep it consistent across services. If I could reasonably just pass the information that I needed, I would. With this central logging however, it becomes basically impossible as I would need to update any number of services after I added something to the central logging. Lets say I started logging request IDs or some new header. I would then have to go to every async request and add that header to the struct of information that I pass in to the async request, Copy that information into the struct, and make sure that the information is then passed into the logging where it needs to be. At this point, I am basically cloning the context already. TLDR: while getting just the data you need would be ideal, sometimes, you don't known what data you need, so you effectively need all of it just in case. I am going to create a CloneContext function in my code to return a read only context, but it would be very nice to have that function as part of echo itself. |


Issue Description
Using echo an asynchronous web server is developed. It accepts request body synchronously; spawns a go routine to process the request data and concurrently returns 200 OK to client
The flow could be imagined to be as below
cto custom middlewarehttp.Requestfrom echo contextc, basically extracting the headers, body, etcc.Set("myKey", "myValue")method--> A go routine is spawned to process this data set inside echo context store
--> Return from middleware by setting a static response -
c.String(200, "Accepted")c.Get("myKey"), we receivenilfor keys set during step3Shouldn't we receive
myValueduring step5?We are suspecting the context might be getting Reset here. We are thinking to clone the data inside echo Context
cinto either a custom context (which implements echo.Context) or maybe use AcquireContext / ReleaseContext utility functions to find a workaroundAny suggestions on a safer way to deal with this?
Working code to debug
Expected behaviour
In the
StreamPushHandlerFunc, we extractAuthDatafrom echo Context and proceed with our further logic to parse the data, which is the else blockActual behaviour
While most of the times we do not see any issue. But in roughly 2-3% of requests (during high traffic on our platform) we could see the
context is nilgetting loggedSteps to reproduce
Run some load onto your webserver using vegeta or any other load test tool
Version/commit
v3.3.10The text was updated successfully, but these errors were encountered: