Skip to content
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

Implement graceful shutdown and propagate request context #468

Merged
merged 10 commits into from Apr 4, 2020

Conversation

johejo
Copy link
Contributor

@johejo johejo commented Mar 30, 2020

Description

Propagate the request context to the Redis client.
It is possible to propagate a context cancel to Redis client if the connection is closed by the HTTP client.
The redis.Cmdable cannot use WithContext, so added the Client interface to handle redis.Client and redis.ClusterClient transparently.

Added handling of Unix signals to http server.

Upgrade go-redis/redis to v7.

Notes

  • Upgrade golang/x/* and google-api-go
  • Migrate fsnotify import from gopkg.in to github.com
  • Replace bmizerany/assert with stretchr/testify/assert

Motivation and Context

In container environment requires more graceful behavior.
Proper handling is also required when disconnected from HTTP clients and forward proxies.
If the context is not propagated properly to read and write to Redis session storage, there is a possibility of unexpected trouble.

How Has This Been Tested?

Added graceful shutdown test.

Checklist:

  • My change requires a change to the documentation or CHANGELOG.
  • I have updated the documentation/CHANGELOG accordingly.
  • I have created a feature (non-master) branch for my PR.

@johejo johejo marked this pull request as ready for review March 30, 2020 21:12
http.go Outdated
sigint := make(chan os.Signal, 1)
signal.Notify(sigint, os.Interrupt, syscall.SIGTERM)
s := <-sigint
logger.Printf("caught signal: %s", s)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth printing what kind of signal this is?

Also, might be worth adding to this that we are now going to shutdown?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking at this log in testing.
This is certainly not necessary, as you say.
I'll remove it.

logger.Printf("caught signal: %s", s)

// We received an interrupt signal, shut down.
if err := srv.Shutdown(context.Background()); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this panic if the server never started correctly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like ErrServerClosed is returned even if the server is not up.
https://github.com/golang/go/blob/master/src/net/http/server.go#L2905

"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
fsnotify "gopkg.in/fsnotify/fsnotify.v1"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this change, I've definitely seen dependency problems in the past, can you double check this should be being done?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this what you're referring to as problem?
fsnotify/fsnotify#328
fsnotify/fsnotify#309
I'll upgrade to v1.4.9 that supports go mod officially.

@@ -290,7 +293,7 @@ func newTicket() (*TicketData, error) {
return nil, fmt.Errorf("failed to create new ticket ID %s", err)
}
// ticketID is hex encoded
ticketID := fmt.Sprintf("%x", rawID)
ticketID := hex.EncodeToString(rawID)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this change the output at all? Just concerned about existing tickets

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change will return exactly the same result.
If you do not like it, I will back to the original implementation.
https://play.golang.org/p/ijrr87i_rox

http_test.go Outdated
srv.ServeHTTP()
}()
time.Sleep(500 * time.Millisecond)
if err := syscall.Kill(os.Getpid(), signal); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this sending a kill signal to the test suite? Does this not cause the test suite to fail? Is there no other way to simulate the signal?

http.go Outdated
Comment on lines 137 to 140
sigint := make(chan os.Signal, 1)
signal.Notify(sigint, os.Interrupt, syscall.SIGTERM)
s := <-sigint
logger.Printf("caught signal: %s", s)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it's better to set up the stop channel in main.go and pass this through, that way it might be easier to test?

Copy link
Member

@JoelSpeed JoelSpeed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking much better, thanks for addressing my comments, just one last comment about the tests and I think this is good to go!

http_test.go Outdated
}()

stop <- struct{}{} // emulate catching signals
wg.Wait()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case this functionality is broken, this test case would hang right? Do you think we can add a timeout somehow?

Copy link
Contributor Author

@johejo johejo Apr 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To find broken case, I added assert to check channel length and add an idiomatic for sync.WaitGroup with timeout.

Propagate the request context to the Redis client.
It is possible to propagate a context cancel to Redis client if the connection is closed by the HTTP client.
The redis.Cmdable cannot use WithContext, so added the Client interface to handle redis.Client and redis.ClusterClient transparently.

Added handling of Unix signals to http server.

Upgrade go-redis/redis to v7.
- Upgrade golang/x/* and google-api-go
- Migrate fsnotify import from gopkg.in to github.com
- Replace bmizerany/assert with stretchr/testify/assert
Copy link
Member

@JoelSpeed JoelSpeed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@JoelSpeed JoelSpeed merged commit c7bfbde into oauth2-proxy:master Apr 4, 2020
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 this pull request may close these issues.

None yet

2 participants