Skip to content

Commit

Permalink
minor(servers): implement both gRPC & HTTP servers (#4)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
cguertin14 authored Jul 3, 2022
1 parent 2451bfc commit b52b69f
Show file tree
Hide file tree
Showing 11 changed files with 500 additions and 76 deletions.
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,21 @@
# server-utils
Utils library for Go HTTP & gRPC servers.

Utils library for Go HTTP & gRPC servers.

## Install this library

To use this library in your own project, simply run this command:
```bash
$ go get github.com/clubcedille/server-utils@latest
...
```

## gRPC Server

The `server-utils` library offers a gRPC implementation of graceful shutdown and real-time status fetching.
See [this example](./examples/grpc-server/main.go) to learn how to use its functions.

## HTTP Server

The `server-utils` library offers an HTTP implementation of graceful shutdown and real-time status fetching.
See [this example](./examples/http-server/main.go) to learn how to use its functions.
25 changes: 0 additions & 25 deletions connection.go

This file was deleted.

27 changes: 27 additions & 0 deletions examples/grpc-server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package main

import (
"context"
"log"

serverutils "github.com/clubcedille/server-utils"
"google.golang.org/grpc"
)

func main() {
// Define your own gRPC server
server := grpc.NewServer()
// register server with protobuf...

// Create and run new gRPC server
grpcServer := serverutils.NewGrpcServer(server)

// Run newly created gRPC server
req := serverutils.RunRequest{
Port: 3000,
ShutdownTimeoutMs: 100000,
}
if err := grpcServer.Run(context.Background(), req); err != nil {
log.Fatalf("fatal error when starting gRPC server: %s\n", err)
}
}
30 changes: 30 additions & 0 deletions examples/http-server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import (
"context"
"fmt"
"log"
"net/http"

serverutils "github.com/clubcedille/server-utils"
)

func main() {
// Define your own gRPC server
port := 3000
server := &http.Server{
Addr: fmt.Sprintf(":%d", port),
}

// Create and run new gRPC server
httpServer := serverutils.NewHttpServer(server)

// Run newly created gRPC server
req := serverutils.RunRequest{
Port: int32(port),
ShutdownTimeoutMs: 100000,
}
if err := httpServer.Run(context.Background(), req); err != nil {
log.Fatalf("fatal error when starting http server: %s\n", err)
}
}
28 changes: 28 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
module github.com/clubcedille/server-utils

go 1.18

require (
github.com/clubcedille/logger v1.0.8
google.golang.org/grpc v1.47.0
)

require (
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.7.7 // indirect
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.4.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/json-iterator/go v1.1.9 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect
golang.org/x/text v0.3.3 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
)
172 changes: 172 additions & 0 deletions go.sum

Large diffs are not rendered by default.

20 changes: 0 additions & 20 deletions grpc_client.go

This file was deleted.

69 changes: 61 additions & 8 deletions grpc_server.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,73 @@
package serverutils

import "context"
import (
"context"
"fmt"
"net"

type GrpcServer struct{}
"google.golang.org/grpc"
)

func NewGrpcServer() *GrpcServer {
return &GrpcServer{}
// GrpcServer represents an instance
// of *grpc.Server, which gracefully shutdowns
// and has a status
type GrpcServer struct {
status Status
server *grpc.Server
}

// NewGrpcServer creates a new instance
// of *GrpcServer
func NewGrpcServer(server *grpc.Server) *GrpcServer {
return &GrpcServer{server: server}
}

// Make sure struct implements interface.
var _ Connection = &GrpcServer{}
var _ Server = &GrpcServer{}
var _ serverOperations = &GrpcServer{}

func (g *GrpcServer) Run(ctx context.Context, req ConnectionRequest) error {
panic("implement me")
func (g *GrpcServer) Run(ctx context.Context, req RunRequest) error {
return startServer(ctx, g, req)
}

func (g *GrpcServer) Status() Status {
panic("implement me")
return g.status
}

func (g *GrpcServer) serve(port int32) error {
// Start a new connection on given port
conn, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
return fmt.Errorf("failed to listen on port %d: %s", port, err)
}

// Update server status to Started
g.status = Running

// Serve gRPC server
err = g.server.Serve(conn)
if err != nil {
return fmt.Errorf("failed to serve gRPC connection: %s", err)
}

// No error occured, exit
return nil
}

func (g *GrpcServer) gracefullyShutdown(ctx context.Context) error {
doneCh := make(chan bool, 1)
go func() {
g.server.GracefulStop()
doneCh <- true

// Update server status to Closed
g.status = Stopped
}()

select {
case <-ctx.Done():
case <-doneCh:
}

return nil
}
22 changes: 0 additions & 22 deletions http.go

This file was deleted.

48 changes: 48 additions & 0 deletions http_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package serverutils

import (
"context"
"net/http"
)

// HttpServer represents an instance
// of *http.Server, which gracefully shutdowns
// and has a status
type HttpServer struct {
status Status
server *http.Server
}

// NewHttpServer creates a new instance
// of *HttpServer
func NewHttpServer(server *http.Server) *HttpServer {
return &HttpServer{server: server}
}

// Make sure struct implements interfaces.
var _ Server = &HttpServer{}
var _ serverOperations = &HttpServer{}

func (s *HttpServer) Run(ctx context.Context, req RunRequest) error {
return startServer(ctx, s, req)
}

func (s *HttpServer) Status() Status {
return s.status
}

func (s *HttpServer) gracefullyShutdown(ctx context.Context) error {
// Update server status to Closed
s.status = Stopped

// Shutdown server
return s.server.Shutdown(ctx)
}

func (s *HttpServer) serve(port int32) error {
// Update server status to Started
s.status = Running

// Start server
return s.server.ListenAndServe()
}
Loading

0 comments on commit b52b69f

Please sign in to comment.