-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #45 from hellofresh/feature/grpc
Added gRPC check implementation
- Loading branch information
Showing
6 changed files
with
191 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ | |
* HTTP | ||
* MongoDB | ||
* MySQL | ||
* gRPC | ||
|
||
## Usage | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package grpc | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/health/grpc_health_v1" | ||
) | ||
|
||
const defaultCheckTimeout = 5 * time.Second | ||
|
||
// Config is the gRPC checker configuration settings container. | ||
type Config struct { | ||
// Target is the address of the gRPC server | ||
Target string | ||
// Service is the name of the gRPC service | ||
Service string | ||
// DialOptions configure how we set up the connection | ||
DialOptions []grpc.DialOption | ||
// CheckTimeout is the duration that health check will try to get gRPC service health status. | ||
// If not set - 5 seconds | ||
CheckTimeout time.Duration | ||
} | ||
|
||
// New creates new gRPC health check | ||
func New(config Config) func() error { | ||
if config.CheckTimeout == 0 { | ||
config.CheckTimeout = defaultCheckTimeout | ||
} | ||
|
||
return func() error { | ||
// Set up a connection to the gRPC server | ||
conn, err := grpc.Dial(config.Target, config.DialOptions...) | ||
if err != nil { | ||
return fmt.Errorf("gRPC health check failed on connect: %w", err) | ||
} | ||
defer conn.Close() | ||
|
||
healthClient := grpc_health_v1.NewHealthClient(conn) | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), config.CheckTimeout) | ||
defer cancel() | ||
|
||
res, err := healthClient.Check(ctx, &grpc_health_v1.HealthCheckRequest{ | ||
Service: config.Service, | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("gRPC health check failed on check call: %w", err) | ||
} | ||
|
||
if res.GetStatus() != grpc_health_v1.HealthCheckResponse_SERVING { | ||
return fmt.Errorf("gRPC service reported as non-serving: %q", res.GetStatus().String()) | ||
} | ||
|
||
return nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package grpc | ||
|
||
import ( | ||
"log" | ||
"net" | ||
"os" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/health" | ||
"google.golang.org/grpc/health/grpc_health_v1" | ||
) | ||
|
||
const ( | ||
addr = ":8080" | ||
service = "HealthTest" | ||
) | ||
|
||
var healthServer *health.Server | ||
|
||
func TestMain(m *testing.M) { | ||
healthServer = health.NewServer() | ||
healthServer.SetServingStatus(service, grpc_health_v1.HealthCheckResponse_SERVING) | ||
|
||
lis, err := net.Listen("tcp", addr) | ||
if err != nil { | ||
log.Fatalf("error setting up tcp listener: %v", err) | ||
} | ||
|
||
server := grpc.NewServer() | ||
grpc_health_v1.RegisterHealthServer(server, healthServer) | ||
|
||
go func() { | ||
if err := server.Serve(lis); err != nil { | ||
log.Fatalf("failed to serve: %v", err) | ||
} | ||
}() | ||
|
||
defer server.Stop() | ||
|
||
os.Exit(m.Run()) | ||
} | ||
|
||
func TestNew_WithServingStatusServing(t *testing.T) { | ||
healthServer.SetServingStatus(service, grpc_health_v1.HealthCheckResponse_SERVING) | ||
|
||
check := New(Config{ | ||
Target: addr, | ||
Service: service, | ||
DialOptions: []grpc.DialOption{ | ||
grpc.WithInsecure(), | ||
}, | ||
}) | ||
|
||
err := check() | ||
require.NoError(t, err) | ||
} | ||
|
||
func TestNew_WithServingStatusUnknown(t *testing.T) { | ||
healthServer.SetServingStatus(service, grpc_health_v1.HealthCheckResponse_UNKNOWN) | ||
|
||
check := New(Config{ | ||
Target: addr, | ||
Service: service, | ||
DialOptions: []grpc.DialOption{ | ||
grpc.WithInsecure(), | ||
}, | ||
}) | ||
|
||
err := check() | ||
require.Error(t, err) | ||
} | ||
|
||
func TestNew_WithServingStatusNotServing(t *testing.T) { | ||
healthServer.SetServingStatus(service, grpc_health_v1.HealthCheckResponse_NOT_SERVING) | ||
|
||
check := New(Config{ | ||
Target: addr, | ||
Service: service, | ||
DialOptions: []grpc.DialOption{ | ||
grpc.WithInsecure(), | ||
}, | ||
}) | ||
|
||
err := check() | ||
require.Error(t, err) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters