From 9b887a14056ec0ef536e75a19c758a1732469adc Mon Sep 17 00:00:00 2001 From: Jonathan Marcantonio Date: Wed, 26 Jun 2024 14:33:20 -0400 Subject: [PATCH] Generalize readyz logic Signed-off-by: Jonathan Marcantonio --- cmd/kessel-relations/wire_gen.go | 3 ++- internal/biz/biz.go | 2 +- internal/biz/relationships.go | 14 +++++++++++ internal/conf/conf.pb.go | 1 - internal/data/spicedb.go | 32 +++++++++++++++++++++---- internal/service/health.go | 40 ++++++++------------------------ 6 files changed, 54 insertions(+), 38 deletions(-) diff --git a/cmd/kessel-relations/wire_gen.go b/cmd/kessel-relations/wire_gen.go index b17faa9..4d8d212 100644 --- a/cmd/kessel-relations/wire_gen.go +++ b/cmd/kessel-relations/wire_gen.go @@ -32,7 +32,8 @@ func wireApp(confServer *conf.Server, confData *conf.Data, logger log.Logger) (* readRelationshipsUsecase := biz.NewReadRelationshipsUsecase(spiceDbRepository, logger) deleteRelationshipsUsecase := biz.NewDeleteRelationshipsUsecase(spiceDbRepository, logger) relationshipsService := service.NewRelationshipsService(logger, createRelationshipsUsecase, readRelationshipsUsecase, deleteRelationshipsUsecase) - healthService := service.NewHealthService() + isBackendAvaliableUsecase := biz.NewIsBackendAvailableUsecase(spiceDbRepository) + healthService := service.NewHealthService(isBackendAvaliableUsecase) checkUsecase := biz.NewCheckUsecase(spiceDbRepository, logger) checkService := service.NewCheckService(logger, checkUsecase) getSubjectsUsecase := biz.NewGetSubjectsUseCase(spiceDbRepository) diff --git a/internal/biz/biz.go b/internal/biz/biz.go index 4eb196d..bb992bc 100644 --- a/internal/biz/biz.go +++ b/internal/biz/biz.go @@ -5,4 +5,4 @@ import ( ) // ProviderSet is biz providers. -var ProviderSet = wire.NewSet(NewCreateRelationshipsUsecase, NewReadRelationshipsUsecase, NewDeleteRelationshipsUsecase, NewCheckUsecase, NewGetSubjectsUseCase) +var ProviderSet = wire.NewSet(NewCreateRelationshipsUsecase, NewReadRelationshipsUsecase, NewDeleteRelationshipsUsecase, NewCheckUsecase, NewGetSubjectsUseCase, NewIsBackendAvailableUsecase) diff --git a/internal/biz/relationships.go b/internal/biz/relationships.go index 62a88d6..46e0b4b 100644 --- a/internal/biz/relationships.go +++ b/internal/biz/relationships.go @@ -2,6 +2,7 @@ package biz import ( "context" + v0 "github.com/project-kessel/relations-api/api/relations/v0" "github.com/go-kratos/kratos/v2/log" @@ -26,6 +27,7 @@ type ZanzibarRepository interface { ReadRelationships(ctx context.Context, filter *v0.RelationTupleFilter, limit uint32, continuation ContinuationToken) (chan *RelationshipResult, chan error, error) DeleteRelationships(context.Context, *v0.RelationTupleFilter) error LookupSubjects(ctx context.Context, subjectType *v0.ObjectType, subject_relation, relation string, resource *v0.ObjectReference, limit uint32, continuation ContinuationToken) (chan *SubjectResult, chan error, error) + IsBackendAvaliable() error } type CheckUsecase struct { @@ -41,6 +43,18 @@ func (rc *CheckUsecase) Check(ctx context.Context, check *v0.CheckRequest) (*v0. return rc.repo.Check(ctx, check) } +type IsBackendAvaliableUsecase struct { + repo ZanzibarRepository +} + +func NewIsBackendAvailableUsecase(repo ZanzibarRepository) *IsBackendAvaliableUsecase { + return &IsBackendAvaliableUsecase{repo: repo} +} + +func (rc *IsBackendAvaliableUsecase) IsBackendAvailable() error { + return rc.repo.IsBackendAvaliable() +} + type CreateRelationshipsUsecase struct { repo ZanzibarRepository log *log.Helper diff --git a/internal/conf/conf.pb.go b/internal/conf/conf.pb.go index e6f4fc3..098868a 100644 --- a/internal/conf/conf.pb.go +++ b/internal/conf/conf.pb.go @@ -1,7 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 -// protoc-gen-go v1.34.1 // protoc v4.25.1 // source: conf/conf.proto diff --git a/internal/data/spicedb.go b/internal/data/spicedb.go index 2539ed8..1b120ff 100644 --- a/internal/data/spicedb.go +++ b/internal/data/spicedb.go @@ -4,12 +4,14 @@ import ( "context" "errors" "fmt" - apiV0 "github.com/project-kessel/relations-api/api/relations/v0" - "github.com/project-kessel/relations-api/internal/biz" - "github.com/project-kessel/relations-api/internal/conf" "io" "os" "strings" + "time" + + apiV0 "github.com/project-kessel/relations-api/api/relations/v0" + "github.com/project-kessel/relations-api/internal/biz" + "github.com/project-kessel/relations-api/internal/conf" v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" "github.com/authzed/authzed-go/v1" @@ -17,11 +19,13 @@ import ( "github.com/go-kratos/kratos/v2/log" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/health/grpc_health_v1" ) // SpiceDbRepository . type SpiceDbRepository struct { - client *authzed.Client + client *authzed.Client + healthClient grpc_health_v1.HealthClient } // NewSpiceDbRepository . @@ -65,11 +69,21 @@ func NewSpiceDbRepository(c *conf.Data, logger log.Logger) (*SpiceDbRepository, return nil, nil, fmt.Errorf("error creating spicedb client: %w", err) } + // Create health client for readyz + conn, err := grpc.NewClient( + c.SpiceDb.Endpoint, + opts..., + ) + if err != nil { + return nil, nil, fmt.Errorf("error creating grpc health client: %w", err) + } + healthClient := grpc_health_v1.NewHealthClient(conn) + cleanup := func() { log.NewHelper(logger).Info("spicedb connection cleanup requested (nothing to clean up)") } - return &SpiceDbRepository{client}, cleanup, nil + return &SpiceDbRepository{client, healthClient}, cleanup, nil } func (s *SpiceDbRepository) LookupSubjects(ctx context.Context, subject_type *apiV0.ObjectType, subject_relation, relation string, object *apiV0.ObjectReference, limit uint32, continuation biz.ContinuationToken) (chan *biz.SubjectResult, chan error, error) { @@ -269,6 +283,14 @@ func (s *SpiceDbRepository) Check(ctx context.Context, check *apiV0.CheckRequest return &apiV0.CheckResponse{Allowed: apiV0.CheckResponse_ALLOWED_FALSE}, nil } +func (s *SpiceDbRepository) IsBackendAvaliable() error { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + _, err := s.healthClient.Check(ctx, &grpc_health_v1.HealthCheckRequest{}) + return err +} + func createSpiceDbRelationshipFilter(filter *apiV0.RelationTupleFilter) *v1.RelationshipFilter { spiceDbRelationshipFilter := &v1.RelationshipFilter{ ResourceType: filter.GetResourceType(), diff --git a/internal/service/health.go b/internal/service/health.go index aafd985..053154a 100644 --- a/internal/service/health.go +++ b/internal/service/health.go @@ -2,50 +2,30 @@ package service import ( "context" - "time" pb "github.com/project-kessel/relations-api/api/health/v1" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/health/grpc_health_v1" + "github.com/project-kessel/relations-api/internal/biz" ) type HealthService struct { pb.UnimplementedKesselHealthServer + backendUseCase *biz.IsBackendAvaliableUsecase } -func NewHealthService() *HealthService { - return &HealthService{} +func NewHealthService(backendUsecase *biz.IsBackendAvaliableUsecase) *HealthService { + return &HealthService{ + backendUseCase: backendUsecase, + } } func (s *HealthService) GetLivez(ctx context.Context, req *pb.GetLivezRequest) (*pb.GetLivezReply, error) { return &pb.GetLivezReply{Status: "OK", Code: 200}, nil } -func (s *HealthService) GetReadyz(ctx context.Context, req *pb.GetReadyzRequest) (*pb.GetReadyzReply, error) { - ready := checkSpiceDBReadyz() - if ready { - return &pb.GetReadyzReply{Status: "OK", Code: 200}, nil - } - return &pb.GetReadyzReply{Status: "Unavailable", Code: 503}, nil -} - -func checkSpiceDBReadyz() bool { - conn, err := grpc.NewClient( - "spicedb:50051", - grpc.WithTransportCredentials(insecure.NewCredentials()), - ) - if err != nil { - return false - } - - client := grpc_health_v1.NewHealthClient(conn) - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - resp, err := client.Check(ctx, &grpc_health_v1.HealthCheckRequest{}) +func (s *HealthService) GetReadyz(ctx context.Context, req *pb.GetReadyzRequest) (*pb.GetReadyzReply, error) { + err := s.backendUseCase.IsBackendAvailable() if err != nil { - return false + return &pb.GetReadyzReply{Status: "Unavailable", Code: 503}, nil } - - return resp.Status == grpc_health_v1.HealthCheckResponse_SERVING + return &pb.GetReadyzReply{Status: "OK", Code: 200}, nil }