Skip to content

Commit 8a4c5f8

Browse files
author
Timo Reimann
committed
Implement graceful shutdown
This change implements graceful shutdown so that a proper driver termination leads to an exit code of zero. Specifically, we handle signals, and let the HTTP and gRPC servers finish requests gracefully. We also remove the Stop() function in favor a context-based approach.
1 parent 8008b09 commit 8a4c5f8

File tree

4 files changed

+43
-15
lines changed

4 files changed

+43
-15
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## unreleased
22

3+
* Implement graceful shutdown
4+
[[GH-238]](https://github.com/digitalocean/csi-digitalocean/pull/238)
35
* Reject requests for block access type
46
[[GH-225]](https://github.com/digitalocean/csi-digitalocean/pull/225)
57
* Assume detached state on 404 during ControllerUnpublishVolume

cmd/do-csi-plugin/main.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@ limitations under the License.
1717
package main
1818

1919
import (
20+
"context"
2021
"flag"
2122
"fmt"
2223
"log"
2324
"os"
25+
"os/signal"
26+
"syscall"
2427

2528
"github.com/digitalocean/csi-digitalocean/driver"
2629
)
@@ -47,7 +50,17 @@ func main() {
4750
log.Fatalln(err)
4851
}
4952

50-
if err := drv.Run(); err != nil {
53+
ctx, cancel := context.WithCancel(context.Background())
54+
defer cancel()
55+
56+
c := make(chan os.Signal, 1)
57+
signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
58+
go func() {
59+
<-c
60+
cancel()
61+
}()
62+
63+
if err := drv.Run(ctx); err != nil {
5164
log.Fatalln(err)
5265
}
5366
}

driver/driver.go

+18-12
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ func NewDriver(ep, token, url, doTag, driverName, address string) (*Driver, erro
164164
}
165165

166166
// Run starts the CSI plugin by communication over the given endpoint
167-
func (d *Driver) Run() error {
167+
func (d *Driver) Run(ctx context.Context) error {
168168
u, err := url.Parse(d.endpoint)
169169
if err != nil {
170170
return fmt.Errorf("unable to parse address: %q", err)
@@ -240,25 +240,31 @@ func (d *Driver) Run() error {
240240

241241
var eg errgroup.Group
242242
eg.Go(func() error {
243+
<-ctx.Done()
244+
return d.httpSrv.Shutdown(context.Background())
245+
})
246+
eg.Go(func() error {
247+
go func() {
248+
<-ctx.Done()
249+
d.log.Info("server stopped")
250+
d.readyMu.Lock()
251+
d.ready = false
252+
d.readyMu.Unlock()
253+
d.srv.GracefulStop()
254+
}()
243255
return d.srv.Serve(grpcListener)
244256
})
245257
eg.Go(func() error {
246-
return d.httpSrv.Serve(httpListener)
258+
err := d.httpSrv.Serve(httpListener)
259+
if err == http.ErrServerClosed {
260+
return nil
261+
}
262+
return err
247263
})
248264

249265
return eg.Wait()
250266
}
251267

252-
// Stop stops the plugin
253-
func (d *Driver) Stop() {
254-
d.readyMu.Lock()
255-
d.ready = false
256-
d.readyMu.Unlock()
257-
258-
d.log.Info("server stopped")
259-
d.srv.Stop()
260-
}
261-
262268
// When building any packages that import version, pass the build/install cmd
263269
// ldflags like so:
264270
// go build -ldflags "-X github.com/digitalocean/csi-digitalocean/driver.version=0.0.1"

driver/driver_test.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,16 @@ func TestDriverSuite(t *testing.T) {
8181
account: &fakeAccountDriver{},
8282
tags: &fakeTagsDriver{},
8383
}
84-
defer driver.Stop()
8584

86-
go driver.Run()
85+
ctx, cancel := context.WithCancel(context.Background())
86+
defer cancel()
87+
88+
go func() {
89+
err := driver.Run(ctx)
90+
if err != nil {
91+
t.Error(err)
92+
}
93+
}()
8794

8895
cfg := &sanity.Config{
8996
TargetPath: os.TempDir() + "/csi-target",

0 commit comments

Comments
 (0)