{"id":19014528,"url":"https://github.com/deeptiman/grpc-connection-library","last_synced_at":"2026-03-07T04:32:28.382Z","repository":{"id":57620727,"uuid":"381093487","full_name":"Deeptiman/grpc-connection-library","owner":"Deeptiman","description":"grpc-connection-library that supports the gRPC client-server connection interface for the developers to use as a gRPC middleware in the application.","archived":false,"fork":false,"pushed_at":"2021-08-19T08:41:46.000Z","size":139,"stargazers_count":14,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-23T00:44:14.128Z","etag":null,"topics":["concurrency","concurrent-programming","golang","golang-library","golang-package","golang-server","grpc","grpc-client","grpc-go","grpc-server","grpc-service","middleware","middleware-framework","network-monitoring","network-programming","ping-pong","pingaccess","retry-library","retry-pattern","retry-policy"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/Deeptiman/grpc-connection-library","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Deeptiman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-06-28T16:18:49.000Z","updated_at":"2023-08-25T14:58:13.000Z","dependencies_parsed_at":"2022-09-02T17:31:55.142Z","dependency_job_id":null,"html_url":"https://github.com/Deeptiman/grpc-connection-library","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Deeptiman/grpc-connection-library","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Deeptiman%2Fgrpc-connection-library","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Deeptiman%2Fgrpc-connection-library/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Deeptiman%2Fgrpc-connection-library/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Deeptiman%2Fgrpc-connection-library/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Deeptiman","download_url":"https://codeload.github.com/Deeptiman/grpc-connection-library/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Deeptiman%2Fgrpc-connection-library/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268717519,"owners_count":24295719,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-04T02:00:09.867Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["concurrency","concurrent-programming","golang","golang-library","golang-package","golang-server","grpc","grpc-client","grpc-go","grpc-server","grpc-service","middleware","middleware-framework","network-monitoring","network-programming","ping-pong","pingaccess","retry-library","retry-pattern","retry-policy"],"created_at":"2024-11-08T19:29:51.389Z","updated_at":"2026-03-07T04:32:28.339Z","avatar_url":"https://github.com/Deeptiman.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# grpc-connection-library\ngrpc-connection-library supports the gRPC client-server connection interface for the developers to use as a gRPC middleware in the application. The library is written in Golang with a concurrency pipeline design pattern to synchronize the gRPC connection pool system.\n\n![GitHub top language](https://img.shields.io/github/languages/top/Deeptiman/grpc-connection-library)  [![Go Report Card](https://goreportcard.com/badge/github.com/Deeptiman/grpc-connection-library)](https://goreportcard.com/report/github.com/Deeptiman/grpc-connection-library)\n\n## Features\n- The gRPC connection flow among server/client synchronized using the Ping/Pong services.\n- gRPC connection library supports connection pool reuse the gRPC client connection instance.\n- Concurrency Pipeline design pattern synchronizes the data flow among several stages while creating the connection pool.\n- The selection process of the gRPC connection instance from the pool is designed using the \u003ca href=\"https://pkg.go.dev/reflect#SelectCase\"\u003ereflect.SelectCase\u003c/a\u003e that supports pseudo-random technique for choosing among different cases.\n- \u003ca href=\"https://github.com/Deeptiman/go-batch\"\u003ego-batch\u003c/a\u003e processing library implemented to divide the connection instances from the pool into batches.\n- The grpc-retry policy helps to retry the failure of gRPC connections with backoff strategy.\n- The \u003ca href=\"https://pkg.go.dev/google.golang.org/grpc/grpclog\"\u003egrpclog\u003c/a\u003e will show the internal connection lifecycle that will be useful to debug the connection flow.\n\n## Installation\n\n````shell\ngo get github.com/Deeptiman/go-connection-library\n````\n\n## Go Docs\nDocumentation at \u003ca href=\"https://pkg.go.dev/github.com/Deeptiman/grpc-connection-library\"\u003epkg.go.dev\u003c/a\u003e\n\n## Example \n\u003cb\u003eClient\u003c/b\u003e:\n \n```````````````````````````````go\npackage main\n\nimport (\n\t\"fmt\"\n\tgrpc \"github.com/Deeptiman/grpc-connection-library/grpc\"\n)\n\nfunc main() {\n\taddress := \"localhost:50051\"\n\tclient, err := grpc.NewGRPCConnection(grpc.WithAddress(address), grpc.WithConnectionType(grpc.Client))\n\tif err != nil {\n\t\tfmt.Println(\"Failed to create GRPC Connection - \", err.Error())\n\t\treturn\n\t}\n\tconn, err := client.GetConn()\n\tif err != nil {\n\t\treturn\n\t}\n\tfmt.Println(\"GRPC Client Connected State= \", conn.GetState().String())\n}\n```````````````````````````````\n\n\u003cb\u003e Server \u003c/b\u003e\n\n```````````````````````````````go\npackage main\n\nimport (\n\t\"fmt\"\n\tgrpc \"github.com/Deeptiman/grpc-connection-library/grpc\"\n)\n\nfunc main() {\n\t\n\tserver, err := grpc.NewGRPCConnection(grpc.WithConnectionType(grpc.Server))\n\tif err != nil {\n\t\tfmt.Println(\"Failed to create GRPC Connection - \", err.Error())\n\t\treturn\n\t}\n\tserver.ListenAndServe()\n}\n```````````````````````````````\n\n## gRPC connection Ping/Pong service\nThe library provides a Ping/Pong service facility to test the client/server connection flow. The service helps to establish connection health check status.\n\n\u003cb\u003eprotos:\u003c/b\u003e\n`````````````````````````````````````proto\nsyntax = \"proto3\";\n\npackage ping;\n\noption go_package = \".;ping\";\n\nimport \"google/protobuf/timestamp.proto\";\n\nservice PingService {\n    rpc SendPongMsg(Request) returns (Response) {}\n}\n\nmessage Request {\n    string message = 1;\n}\n\nmessage Pong {\n    int32 index = 1;\n    string message = 2;\n    google.protobuf.Timestamp received_on = 3;\n}\n\nmessage Response {\n    Pong pong = 1;\n}\n`````````````````````````````````````\n\u003cb\u003e Server:\u003c/b\u003e\n1. ListenAndServe will start listening to the specific serverPort with the \u003cb\u003e\"tcp\"\u003c/b\u003e network type. \n2. After the server listener socket is opened, the initial Ping request gets registered that can be used by any gRPC clients to sent Ping-Pong request to check the client-server gRPC connection health status.\n\n``````````````````````````````````go\ngrpcServer := grpc.NewServer(serverOptions...)\n// Register the Ping service request\npb.RegisterPingServiceServer(grpcServer, \u0026pb.PingService{})\nif err = grpcServer.Serve(listener); err != nil {\n\tg.log.Errorln(\"failed start server - %v\", err)\n\tg.log.Fatal(err)\n\treturn err\n}\n``````````````````````````````````\n\n\u003cb\u003e Client: \u003c/b\u003e\n1. gRPC client connection instance creates Ping service to test connection health.\n2. The \u003cb\u003eSendPingMsg\u003c/b\u003e sends a test msg to the target server address to get the Pong response msg back to verify the connection flow.\n\n`````````````````````````````````go\nconn, err := grpc.Dial(address, opts...)\nif err != nil {\n    c.Log.Fatal(err)\n    return nil, err\n}\nclient := pb.NewPingServiceClient(c.Conn)\nrespMsg, err := pb.SendPingMsg(client)\nif err != nil {\n   return nil, err\n}\nc.Log.Infoln(\"GRPC Pong msg - \", respMsg)\n`````````````````````````````````\n\n## Concurrency Pipeline for gRPC Connection Pool\n1. \u003ca href=\"https://github.com/Deeptiman/grpc-connection-library/blob/master/pool/connection_pool.go#L170\"\u003eConnPoolPipeline()\u003c/a\u003e follows the concurrency pipeline technique to create a connection pool in a higher concurrent scenarios. The pipeline has several stages that use the \u003cb\u003eFan-In, Fan-Out\u003c/b\u003e technique to process the data pipeline using channels.\n2. The entire process of creating the connection pool becomes a powerful function using the pipeline technique. The four stages work as a generator pattern for the connection pool.\n\n### Pipeline Stages\n#### Stage-1: \nThis stage will create the initial gRPC connection instance that gets passed to the next pipeline stage for replication.\n\t\n `````````````````````````````````````````````````go\n connInstancefn := func(done chan interface{}) \u003c-chan *grpc.ClientConn {\n\n   connCh := make(chan *grpc.ClientConn)\n\n   conn, err := c.ClientConn()\n   if err != nil {\n\tdone \u003c- err\n   }\n\n    go func() {\n       c.Log.Infoln(\"1#connInstance ...\")\n       defer close(connCh)\n\t select {\n\t   case connCh \u003c- conn:\n\t     c.Log.Infoln(\"GRPC Connection Status - \", conn.GetState().String())\n\t }\n    }()\n  return connCh \n}\n`````````````````````````````````````````````````\n#### Stage-2: \nThe cloning process of the initial gRPC connection object will begin here. The connection instance gets passed to the next stage iteratively via channels.\n\n`````````````````````````````````````````````````go\nconnReplicasfn := func(connInstanceCh \u003c-chan *grpc.ClientConn) \u003c-chan *grpc.ClientConn {\n\tconnInstanceReplicaCh := make(chan *grpc.ClientConn)\n\t\tgo func() {\n\t\t\tc.Log.Infoln(\"2#connReplicas ...\")\n\t\t\tdefer close(connInstanceReplicaCh)\n\t\t\tfor conn := range connInstanceCh {\n\t\t\t\tfor i := 0; uint64(i) \u003c c.MaxPoolSize; i++ {\n\t\t\t\t\tselect {\n\t\t\t\t\tcase connInstanceReplicaCh \u003c- conn:\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\treturn connInstanceReplicaCh\n}\n`````````````````````````````````````````````````\n#### Stage-3: \nThis stage will start the batch processing using the \u003ca href=\"https://github.com/Deeptiman/go-batch\"\u003egithub.com/Deeptiman/go-batch\u003c/a\u003e library. The MaxPoolSize is divided into multiple batches and released via a supply channel from go-batch library internal implementation.\n\n`````````````````````````````````````````````````go\nconnBatchfn := func(connInstanceCh \u003c-chan *grpc.ClientConn) chan []batch.BatchItems {\n\n\t\tgo func() {\n\t\t\tc.Log.Infoln(\"3#connBatch ...\")\n\t\t\tc.ConnInstanceBatch.StartBatchProcessing()\n\t\t\tfor conn := range connInstanceCh {\n\t\t\t\tselect {\n\t\t\t\tcase c.ConnInstanceBatch.Item \u003c- conn:\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\treturn c.ConnInstanceBatch.Consumer.Supply.ClientSupplyCh\n}\n\n`````````````````````````````````````````````````\n#### Stage-4:\nThe connection queue reads through the go-batch client supply channel and stores the connection instances as channel case in \u003cb\u003e[]reflect.SelectCase\u003c/b\u003e. So, whenever the client requests a connection instance, \u003cb\u003ereflect.SelectCase\u003c/b\u003e retrieves the conn instances from the case using the pseudo-random technique.\n\n`````````````````````````````````````````````````go\nconnEnqueuefn := func(connSupplyCh \u003c-chan []batch.BatchItems) \u003c-chan batch.BatchItems {\n\treceiveBatchCh := make(chan batch.BatchItems)\n\t\tgo func() {\n\t\t\tc.Log.Infoln(\"4#connEnqueue ...\")\n\t\t\tdefer close(receiveBatchCh)\n\t\t\tfor supply := range connSupplyCh {\n\n\t\t\t\tfor _, s := range supply {\n\t\t\t\t\tc.EnqueConnBatch(s)\n\t\t\t\t\tselect {\n\t\t\t\t\tcase receiveBatchCh \u003c- s:\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\treturn receiveBatchCh\n}\n`````````````````````````````````````````````````\n#### Run the pipeline:\n`````````````````````````````````````````````````go\nfor s := range connEnqueuefn(connBatchfn(connReplicasfn(connInstancefn(done)))) {\n\tgo func(s batch.BatchItems) {\n\t\tatomic.AddUint64(\u0026ConnPoolPipeline, 1)\n\t\tif c.GetConnPoolSize() == c.MaxPoolSize {\n\t\t\tselect {\n\t\t\tcase pipelineDoneChan \u003c- \"Done\":\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}(s)\n}\n`````````````````````````````````````````````````\n\n## Batch Processing Item structure in the connection pool\n\n`````````````````````````````````````````````````go\ntype BatchItems struct {\n   Id      int         `json:\"id\"`\n   BatchNo int         `json:\"batchNo\"`\n   Item    interface{} `json:\"item\"`\n}\n`````````````````````````````````````````````````\n#### Scenario:\nThere are \u003cb\u003e12\u003c/b\u003e gRPC connection instances stored in \u003cb\u003e3\u003c/b\u003e batches.\n\t\u003ctable\u003e\n\t\u003ctr\u003e\n\t\u003cth align=\"left\"\u003eBatch\u003c/th\u003e\t\n\t\u003cth align=\"left\"\u003eItems\u003c/th\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\u003ctd align=\"top\"\u003eBatch-1\u003c/td\u003e\n\t\u003ctd\u003e\n\t\u003ctable\u003e\n\t\u003ctr\u003e\u003ctd\u003e{Id: 1, BatchNo: 1, Item: *grpc.ClientConn}\u003c/td\u003e\u003c/tr\u003e\n\t\u003ctr\u003e\u003ctd\u003e{Id: 2, BatchNo: 1, Item: *grpc.ClientConn}\u003c/td\u003e\u003c/tr\u003e\n\t\u003ctr\u003e\u003ctd\u003e{Id: 3, BatchNo: 1, Item: *grpc.ClientConn}\u003c/td\u003e\u003c/tr\u003e\n\t\u003ctr\u003e\u003ctd\u003e{Id: 4, BatchNo: 1, Item: *grpc.ClientConn}\u003c/td\u003e\u003c/tr\u003e\n\t\u003c/table\u003e\n\t\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\u003ctd align=\"top\"\u003eBatch-2\u003c/td\u003e\n\t\u003ctd\u003e\n\t\u003ctable\u003e\n\t\u003ctr\u003e\u003ctd\u003e{Id: 1, BatchNo: 2, Item: *grpc.ClientConn}\u003c/td\u003e\u003c/tr\u003e\n\t\u003ctr\u003e\u003ctd\u003e{Id: 2, BatchNo: 2, Item: *grpc.ClientConn}\u003c/td\u003e\u003c/tr\u003e\n\t\u003ctr\u003e\u003ctd\u003e{Id: 3, BatchNo: 2, Item: *grpc.ClientConn}\u003c/td\u003e\u003c/tr\u003e\n\t\u003ctr\u003e\u003ctd\u003e{Id: 4, BatchNo: 2, Item: *grpc.ClientConn}\u003c/td\u003e\u003c/tr\u003e\n\t\u003c/table\u003e\n\t\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\u003ctd align=\"top\"\u003eBatch-3\u003c/td\u003e\n\t\u003ctd\u003e\n\t\u003ctable\u003e\n\t\u003ctr\u003e\u003ctd\u003e{Id: 1, BatchNo: 3, Item: *grpc.ClientConn}\u003c/td\u003e\u003c/tr\u003e\n\t\u003ctr\u003e\u003ctd\u003e{Id: 2, BatchNo: 3, Item: *grpc.ClientConn}\u003c/td\u003e\u003c/tr\u003e\n\t\u003ctr\u003e\u003ctd\u003e{Id: 3, BatchNo: 3, Item: *grpc.ClientConn}\u003c/td\u003e\u003c/tr\u003e\n\t\u003ctr\u003e\u003ctd\u003e{Id: 4, BatchNo: 3, Item: *grpc.ClientConn}\u003c/td\u003e\u003c/tr\u003e\n\t\u003c/table\u003e\n\t\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003c/table\u003e\n\nSo, the connection pool stores the connection instances as a batch processing array []batch.BatchItems{}.\n\n## gRPC Connection Pool Selection Process\nThe connection instance selection from the pool happens using the \u003cb\u003ereflect.SelectCase\u003c/b\u003e package. The connection instances stored as a channel case in the []reflect.SelectCase{}. The search for any available connection instance from the pool works as a \u003cb\u003epseudo-random\u003c/b\u003e case selector.\n\n### Store conn instances into reflect.SelectCase\n````````````````````````````````````````````````go\n// The enqueCh will store the array of channel batchItems and get added to the reflect.SelectCase.\n   enqueCh    []chan batch.BatchItems\n   \n   q.itemSelect[i] = reflect.SelectCase{\n\t\tDir: reflect.SelectRecv, \n\t\tChan: reflect.ValueOf(q.enqueCh[i])\n   }\n````````````````````````````````````````````````\n\n### Retrive conn instance from pool of cases\n````````````````````````````````````````````````go\nfor {\n\tchosen, rcv, ok := reflect.Select(q.itemSelect)\n\tif !ok {\n\t\tq.log.Infoln(\"Conn Batch Instance Not Chosen = \", chosen)\n\t\tcontinue\n\t}\n\tq.log.Infoln(\"SelectCase\", \"Batch Conn : chosen = \", chosen)\n\n\t// Remove the selected case from the array to avoid the duplicate choosing of the cases.\n\tq.itemSelect = append(q.itemSelect[:chosen], q.itemSelect[chosen+1:]...)\n\n\treturn rcv.Interface().(batch.BatchItems)\n}\n````````````````````````````````````````````````\n## License\nThis project is licensed under the \u003ca href=\"https://github.com/Deeptiman/grpc-connection-library/blob/master/LICENSE\"\u003eMIT License\u003c/a\u003e\n\n## References\n1. \u003ca href=\"https://github.com/grpc-ecosystem/go-grpc-middleware\"\u003eGo gRPC Middleware\u003c/a\u003e\n2. \u003ca href=\"https://www.oreilly.com/library/view/concurrency-in-go/9781491941294/ch04.html\"\u003eConcurrency Pipeline Patterns\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeeptiman%2Fgrpc-connection-library","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdeeptiman%2Fgrpc-connection-library","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeeptiman%2Fgrpc-connection-library/lists"}