Skip to content

Commit c120ffd

Browse files
committed
examples/features/gracefulstop: add example to demonstrate server graceful stop
1 parent 87f0254 commit c120ffd

File tree

3 files changed

+183
-0
lines changed

3 files changed

+183
-0
lines changed
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Graceful Stop
2+
3+
This example demonstrates how to gracefully stop a gRPC server using Server.GracefulStop().
4+
5+
## How to run
6+
7+
Start the server which will listen to incoming gRPC requests as well as OS
8+
interrupt signals (SIGINT/SIGTERM). After receiving interrupt signal, it calls
9+
`s.GracefulStop()` to gracefully shut down the server. If graceful shutdown
10+
doesn't happen in time, server is stopped forcefully.
11+
12+
```sh
13+
$ go run server/main.go
14+
```
15+
16+
In a separate terminal, start the client which will send multiple requests to
17+
the server with some delay between each request.
18+
19+
```sh
20+
$ go run client/main.go
21+
```
22+
23+
Use Ctrl+C or SIGTERM to signal the server to shut down.
24+
25+
The server begins a graceful stop:
26+
- It finishes ongoing requests.
27+
- Rejects new incoming requests.
28+
29+
The client will notice the server's shutdown when a request fails.
30+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
*
3+
* Copyright 2024 gRPC authors.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
// Binary client demonstrates sending multiple requests to server and observe
19+
// graceful stop.
20+
package main
21+
22+
import (
23+
"context"
24+
"flag"
25+
"log"
26+
"time"
27+
28+
"google.golang.org/grpc"
29+
"google.golang.org/grpc/codes"
30+
"google.golang.org/grpc/credentials/insecure"
31+
pb "google.golang.org/grpc/examples/helloworld/helloworld"
32+
"google.golang.org/grpc/status"
33+
)
34+
35+
var addr = flag.String("addr", "localhost:50052", "the address to connect to")
36+
37+
func main() {
38+
flag.Parse()
39+
40+
// Set up a connection to the server.
41+
conn, err := grpc.NewClient(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
42+
if err != nil {
43+
log.Fatalf("Failed to connect: %v", err)
44+
}
45+
defer conn.Close()
46+
c := pb.NewGreeterClient(conn)
47+
48+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
49+
defer cancel()
50+
51+
for i := 1; i <= 10; i++ {
52+
log.Printf("Calling SayHello %d time", i)
53+
r, err := c.SayHello(ctx, &pb.HelloRequest{})
54+
if err != nil {
55+
if status.Code(err) != codes.InvalidArgument {
56+
log.Printf("Received unexpected error: %v", err)
57+
continue
58+
}
59+
log.Printf("Received error: %v", err)
60+
continue
61+
}
62+
log.Printf("Received response: %s", r.Message)
63+
time.Sleep(time.Second)
64+
}
65+
66+
log.Printf("Client finished interaction with server.")
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
*
3+
* Copyright 2024 gRPC authors.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
// Binary server demonstrates how to gracefully stop a gRPC server.
19+
package main
20+
21+
import (
22+
"context"
23+
"flag"
24+
"fmt"
25+
"log"
26+
"net"
27+
"os"
28+
"os/signal"
29+
"syscall"
30+
"time"
31+
32+
"google.golang.org/grpc"
33+
pb "google.golang.org/grpc/examples/helloworld/helloworld"
34+
)
35+
36+
var port = flag.Int("port", 50052, "port number")
37+
38+
// server is used to implement helloworld.GreeterServer.
39+
type server struct {
40+
pb.UnimplementedGreeterServer
41+
}
42+
43+
// SayHello implements helloworld.GreeterServer.
44+
func (s *server) SayHello(_ context.Context, _ *pb.HelloRequest) (*pb.HelloReply, error) {
45+
return &pb.HelloReply{Message: "Hello"}, nil
46+
}
47+
48+
func main() {
49+
flag.Parse()
50+
51+
address := fmt.Sprintf(":%v", *port)
52+
lis, err := net.Listen("tcp", address)
53+
if err != nil {
54+
log.Fatalf("failed to listen: %v", err)
55+
}
56+
57+
// Create a channel to listen for OS signals.
58+
stop := make(chan os.Signal, 1)
59+
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
60+
61+
s := grpc.NewServer()
62+
pb.RegisterGreeterServer(s, &server{})
63+
64+
go func() {
65+
// Wait for an OS signal for graceful shutdown.
66+
<-stop
67+
fmt.Println("Shutting down server...")
68+
s.GracefulStop()
69+
close(stop)
70+
}()
71+
72+
if err := s.Serve(lis); err != nil {
73+
log.Fatalf("failed to serve: %v", err)
74+
}
75+
76+
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
77+
defer cancel()
78+
79+
select {
80+
case <-stop:
81+
log.Printf("Server stopped gracefully")
82+
case <-ctx.Done():
83+
log.Printf("Graceful stop timeout reached. Forcing server stop.")
84+
s.Stop() // Forceful stop
85+
}
86+
}

0 commit comments

Comments
 (0)