Skip to content

golang-http does not allow graceful request cancelling #40

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

Closed
LucasRoesler opened this issue Apr 5, 2020 · 5 comments · Fixed by #41
Closed

golang-http does not allow graceful request cancelling #40

LucasRoesler opened this issue Apr 5, 2020 · 5 comments · Fixed by #41

Comments

@LucasRoesler
Copy link
Member

Because the go-function-sdk does not propagate the original request context in the Request object, the handler can not correctly respond to the request being cancelled by the user. In the Go stdlib this information is generally conveyed by the checking if request.Context() is done.

If the handler has an expensive operation that should be canceled and reverted, e.g. a DB transaction, this would be impossible because the handler can not check for the early cancellation.

We should be able to see this by creating a handler that prints/counts to a large number, issuing a request and then immediately cancelling. The handler should continue to count even after the user aborts the request.

For example, using this

# stack.yml
version: 1.0
provider:
  name: openfaas
  gateway: http://127.0.0.1:808

configuration:
  templates:
    - name: golang-http
      source: https://github.com/openfaas-incubator/golang-http-template

functions:
  counter:
    lang: golang-http
    handler: ./counter
    image: counter:latest
# counter/handler.go
package function

import (
	"fmt"
	"net/http"

	handler "github.com/openfaas-incubator/go-function-sdk"
)

// Handle a function invocation
func Handle(req handler.Request) (handler.Response, error) {
	var err error

	for i := 0; i < 1000; i++ {
		fmt.Printf("count %d\n", i)
	}

	message := fmt.Sprintf("Hello world, input was: %s", string(req.Body))
	return handler.Response{
		Body:       []byte(message),
		StatusCode: http.StatusOK,
	}, err
}

Build and run the function

faas-cli build -f stack.yml
docker run --rm -p 8080:8080 counter:latest 

Then in a new terminal

curl localhost:8080 -d "anything"
<ctrl>-c

You will see the function start and then continue even after you ctrl-c the curl request. This is because the handler has not even attempted to check for the abort. But it is not currently possible to do this because the context is not available.

@alexellis
Copy link
Member

Thanks for this example, please can you now show us how it would work differently with the cancellation in place?

@LucasRoesler
Copy link
Member Author

LucasRoesler commented Apr 5, 2020

I was just about to add that, I would expect this function to stop as soon as the ctrl-c happens

package function

import (
	"fmt"
	"net/http"

	handler "github.com/openfaas-incubator/go-function-sdk"
)

// Handle a function invocation
func Handle(req handler.Request) (handler.Response, error) {
	var err error

	for i := 0; i < 10000; i++ {
		if req.Context().Err() != nil  {
			return handler.Response{}, fmt.Errorf("request cancelled")
		}
		fmt.Printf("count %d\n", i)
	}

	message := fmt.Sprintf("Hello world, input was: %s", string(req.Body))
	return handler.Response{
		Body:       []byte(message),
		StatusCode: http.StatusOK,
	}, err
}

@alexellis
Copy link
Member

This would make a good addition to the README.md as an example:

I.e. "How to cancel a long running operation" or similar

@alexellis
Copy link
Member

Is this issue resloved now?

@LucasRoesler
Copy link
Member Author

I will PR the updated docs against this, but i think it is fixed once the of-watchdog is updated in the templates as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants