Skip to content

Commit b52b69f

Browse files
authored
minor(servers): implement both gRPC & HTTP servers (#4)
* Add examples for http & grpc * Update dependencies * Progress on http + grpc servers. * Update examples + docs * Remove connection file, rename stuff, finish * Comment out closing err channel * Added logs, closing ch * Defer closing of channel * Fix status for grpc + logs * Comment out closing of ch * Channel closing testing * Fix grpc shutdown done channel closing * Fix closing of done ch
1 parent 2451bfc commit b52b69f

File tree

11 files changed

+500
-76
lines changed

11 files changed

+500
-76
lines changed

README.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,21 @@
11
# server-utils
2-
Utils library for Go HTTP & gRPC servers.
2+
3+
Utils library for Go HTTP & gRPC servers.
4+
5+
## Install this library
6+
7+
To use this library in your own project, simply run this command:
8+
```bash
9+
$ go get github.com/clubcedille/server-utils@latest
10+
...
11+
```
12+
13+
## gRPC Server
14+
15+
The `server-utils` library offers a gRPC implementation of graceful shutdown and real-time status fetching.
16+
See [this example](./examples/grpc-server/main.go) to learn how to use its functions.
17+
18+
## HTTP Server
19+
20+
The `server-utils` library offers an HTTP implementation of graceful shutdown and real-time status fetching.
21+
See [this example](./examples/http-server/main.go) to learn how to use its functions.

connection.go

Lines changed: 0 additions & 25 deletions
This file was deleted.

examples/grpc-server/main.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"log"
6+
7+
serverutils "github.com/clubcedille/server-utils"
8+
"google.golang.org/grpc"
9+
)
10+
11+
func main() {
12+
// Define your own gRPC server
13+
server := grpc.NewServer()
14+
// register server with protobuf...
15+
16+
// Create and run new gRPC server
17+
grpcServer := serverutils.NewGrpcServer(server)
18+
19+
// Run newly created gRPC server
20+
req := serverutils.RunRequest{
21+
Port: 3000,
22+
ShutdownTimeoutMs: 100000,
23+
}
24+
if err := grpcServer.Run(context.Background(), req); err != nil {
25+
log.Fatalf("fatal error when starting gRPC server: %s\n", err)
26+
}
27+
}

examples/http-server/main.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"net/http"
8+
9+
serverutils "github.com/clubcedille/server-utils"
10+
)
11+
12+
func main() {
13+
// Define your own gRPC server
14+
port := 3000
15+
server := &http.Server{
16+
Addr: fmt.Sprintf(":%d", port),
17+
}
18+
19+
// Create and run new gRPC server
20+
httpServer := serverutils.NewHttpServer(server)
21+
22+
// Run newly created gRPC server
23+
req := serverutils.RunRequest{
24+
Port: int32(port),
25+
ShutdownTimeoutMs: 100000,
26+
}
27+
if err := httpServer.Run(context.Background(), req); err != nil {
28+
log.Fatalf("fatal error when starting http server: %s\n", err)
29+
}
30+
}

go.mod

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
11
module github.com/clubcedille/server-utils
22

33
go 1.18
4+
5+
require (
6+
github.com/clubcedille/logger v1.0.8
7+
google.golang.org/grpc v1.47.0
8+
)
9+
10+
require (
11+
github.com/gin-contrib/sse v0.1.0 // indirect
12+
github.com/gin-gonic/gin v1.7.7 // indirect
13+
github.com/go-playground/locales v0.13.0 // indirect
14+
github.com/go-playground/universal-translator v0.17.0 // indirect
15+
github.com/go-playground/validator/v10 v10.4.1 // indirect
16+
github.com/golang/protobuf v1.5.2 // indirect
17+
github.com/json-iterator/go v1.1.9 // indirect
18+
github.com/leodido/go-urn v1.2.0 // indirect
19+
github.com/mattn/go-isatty v0.0.12 // indirect
20+
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
21+
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
22+
github.com/sirupsen/logrus v1.8.1 // indirect
23+
github.com/ugorji/go/codec v1.1.7 // indirect
24+
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
25+
golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect
26+
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect
27+
golang.org/x/text v0.3.3 // indirect
28+
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
29+
google.golang.org/protobuf v1.27.1 // indirect
30+
gopkg.in/yaml.v2 v2.2.8 // indirect
31+
)

go.sum

Lines changed: 172 additions & 0 deletions
Large diffs are not rendered by default.

grpc_client.go

Lines changed: 0 additions & 20 deletions
This file was deleted.

grpc_server.go

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,73 @@
11
package serverutils
22

3-
import "context"
3+
import (
4+
"context"
5+
"fmt"
6+
"net"
47

5-
type GrpcServer struct{}
8+
"google.golang.org/grpc"
9+
)
610

7-
func NewGrpcServer() *GrpcServer {
8-
return &GrpcServer{}
11+
// GrpcServer represents an instance
12+
// of *grpc.Server, which gracefully shutdowns
13+
// and has a status
14+
type GrpcServer struct {
15+
status Status
16+
server *grpc.Server
17+
}
18+
19+
// NewGrpcServer creates a new instance
20+
// of *GrpcServer
21+
func NewGrpcServer(server *grpc.Server) *GrpcServer {
22+
return &GrpcServer{server: server}
923
}
1024

1125
// Make sure struct implements interface.
12-
var _ Connection = &GrpcServer{}
26+
var _ Server = &GrpcServer{}
27+
var _ serverOperations = &GrpcServer{}
1328

14-
func (g *GrpcServer) Run(ctx context.Context, req ConnectionRequest) error {
15-
panic("implement me")
29+
func (g *GrpcServer) Run(ctx context.Context, req RunRequest) error {
30+
return startServer(ctx, g, req)
1631
}
1732

1833
func (g *GrpcServer) Status() Status {
19-
panic("implement me")
34+
return g.status
35+
}
36+
37+
func (g *GrpcServer) serve(port int32) error {
38+
// Start a new connection on given port
39+
conn, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
40+
if err != nil {
41+
return fmt.Errorf("failed to listen on port %d: %s", port, err)
42+
}
43+
44+
// Update server status to Started
45+
g.status = Running
46+
47+
// Serve gRPC server
48+
err = g.server.Serve(conn)
49+
if err != nil {
50+
return fmt.Errorf("failed to serve gRPC connection: %s", err)
51+
}
52+
53+
// No error occured, exit
54+
return nil
55+
}
56+
57+
func (g *GrpcServer) gracefullyShutdown(ctx context.Context) error {
58+
doneCh := make(chan bool, 1)
59+
go func() {
60+
g.server.GracefulStop()
61+
doneCh <- true
62+
63+
// Update server status to Closed
64+
g.status = Stopped
65+
}()
66+
67+
select {
68+
case <-ctx.Done():
69+
case <-doneCh:
70+
}
71+
72+
return nil
2073
}

http.go

Lines changed: 0 additions & 22 deletions
This file was deleted.

http_server.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package serverutils
2+
3+
import (
4+
"context"
5+
"net/http"
6+
)
7+
8+
// HttpServer represents an instance
9+
// of *http.Server, which gracefully shutdowns
10+
// and has a status
11+
type HttpServer struct {
12+
status Status
13+
server *http.Server
14+
}
15+
16+
// NewHttpServer creates a new instance
17+
// of *HttpServer
18+
func NewHttpServer(server *http.Server) *HttpServer {
19+
return &HttpServer{server: server}
20+
}
21+
22+
// Make sure struct implements interfaces.
23+
var _ Server = &HttpServer{}
24+
var _ serverOperations = &HttpServer{}
25+
26+
func (s *HttpServer) Run(ctx context.Context, req RunRequest) error {
27+
return startServer(ctx, s, req)
28+
}
29+
30+
func (s *HttpServer) Status() Status {
31+
return s.status
32+
}
33+
34+
func (s *HttpServer) gracefullyShutdown(ctx context.Context) error {
35+
// Update server status to Closed
36+
s.status = Stopped
37+
38+
// Shutdown server
39+
return s.server.Shutdown(ctx)
40+
}
41+
42+
func (s *HttpServer) serve(port int32) error {
43+
// Update server status to Started
44+
s.status = Running
45+
46+
// Start server
47+
return s.server.ListenAndServe()
48+
}

0 commit comments

Comments
 (0)