{"id":50454238,"url":"https://github.com/mizcausevic-dev/grpc-mesh-shadow","last_synced_at":"2026-06-01T01:05:57.718Z","repository":{"id":357458234,"uuid":"1236282633","full_name":"mizcausevic-dev/grpc-mesh-shadow","owner":"mizcausevic-dev","description":"Typed gRPC shadow traffic client. Mirrors requests from a stable primary to an under-test candidate; diffs responses asynchronously; returns the primary to your caller. Sampling, timeouts, pluggable sinks. bufconn-tested.","archived":false,"fork":false,"pushed_at":"2026-05-12T21:39:49.000Z","size":36,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-12T22:28:48.102Z","etag":null,"topics":["ai-governance","canary","golang","grpc","platform-engineering","protobuf","service-mesh","shadow-traffic","sre"],"latest_commit_sha":null,"homepage":"https://github.com/mizcausevic-dev/grpc-mesh-shadow","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mizcausevic-dev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-12T05:37:06.000Z","updated_at":"2026-05-12T21:39:53.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mizcausevic-dev/grpc-mesh-shadow","commit_stats":null,"previous_names":["mizcausevic-dev/grpc-mesh-shadow"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/mizcausevic-dev/grpc-mesh-shadow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mizcausevic-dev%2Fgrpc-mesh-shadow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mizcausevic-dev%2Fgrpc-mesh-shadow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mizcausevic-dev%2Fgrpc-mesh-shadow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mizcausevic-dev%2Fgrpc-mesh-shadow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mizcausevic-dev","download_url":"https://codeload.github.com/mizcausevic-dev/grpc-mesh-shadow/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mizcausevic-dev%2Fgrpc-mesh-shadow/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33755379,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-31T02:00:06.040Z","response_time":95,"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":["ai-governance","canary","golang","grpc","platform-engineering","protobuf","service-mesh","shadow-traffic","sre"],"created_at":"2026-06-01T01:05:57.640Z","updated_at":"2026-06-01T01:05:57.713Z","avatar_url":"https://github.com/mizcausevic-dev.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# grpc-mesh-shadow\n\nA typed gRPC **shadow traffic** client — primary backend's responses go to your users, candidate backend's responses get diffed in the background. Built for the boring-but-critical SRE problem of testing a new service version against production traffic *without* exposing users to its bugs.\n\n## What it does\n\nWrap any `pb.PricingServiceClient` pair with `shadow.NewClient(primary, candidate, sink, cfg)`. Every call goes to the **primary**; the response is returned to your code immediately. In parallel (or synchronously for tests), the **candidate** is called with the same request. The two responses are diffed; mismatches, errors, and latency profiles are emitted to a configurable `DiffSink`.\n\nUse it when:\n- You're rewriting a hot-path service and need confidence the new version computes the same results\n- You're migrating between providers (e.g. two pricing engines) and want continuous comparison\n- You want production traffic in your eval harness without putting the candidate in the user path\n\n## Quickstart\n\n```bash\ngo install github.com/mizcausevic-dev/grpc-mesh-shadow/cmd/shadow@latest\nshadow   # runs the in-process demo\n```\n\nThe demo output:\n\n```\nshadow demo: 5 quotes through primary, mirrored to candidate\n--------------------------------------------------------------\nclient received: sku=WIDGET-9 qty=1 total=$10.00 algo=primary-v1\nclient received: sku=WIDGET-9 qty=2 total=$20.00 algo=primary-v1\nclient received: sku=WIDGET-9 qty=3 total=$30.00 algo=primary-v1\nclient received: sku=WIDGET-9 qty=4 total=$40.00 algo=primary-v1\nclient received: sku=WIDGET-9 qty=5 total=$50.00 algo=primary-v1\n\nshadow events:\n  shadow DIVERGENT kind=value_diff sku=WIDGET-9 tenant=tnt_demo ...\n  (5 total)\n\ndivergent: 5/5\n```\n\n## Library usage\n\n```go\nimport (\n    \"github.com/mizcausevic-dev/grpc-mesh-shadow\"\n    pb \"github.com/mizcausevic-dev/grpc-mesh-shadow/proto\"\n)\n\nprimary := pb.NewPricingServiceClient(primaryConn)\ncandidate := pb.NewPricingServiceClient(candidateConn)\nsink := \u0026shadow.MemoryDiffSink{}   // or write a custom DiffSink\n\ncfg := shadow.DefaultConfig()\ncfg.SamplingRate = 0.1   // mirror 10% of traffic\nclient := shadow.NewClient(primary, candidate, sink, cfg)\n\nresp, err := client.Quote(ctx, req)  // returns primary; candidate runs in background\n```\n\n## Config\n\n| Field | Default | What |\n|---|---|---|\n| `CandidateTimeout` | `5s` | How long the candidate has to respond. Has no effect on primary latency. |\n| `SyncShadow` | `false` | Block on candidate before returning primary. Off in production; on for deterministic tests. |\n| `SamplingRate` | `1.0` | Fraction of primary requests mirrored to candidate. |\n\n## DiffEvent\n\n```go\ntype DiffEvent struct {\n    Request        *pb.QuoteRequest\n    PrimaryResp    *pb.QuoteResponse\n    CandidateResp  *pb.QuoteResponse\n    PrimaryErr     error\n    CandidateErr   error\n    PrimaryLatency time.Duration\n    ShadowLatency  time.Duration\n    Divergent      bool\n    DivergenceKind string   // \"primary_error\" | \"candidate_error\" | \"value_diff\" | \"\"\n}\n```\n\nImplement your own `DiffSink` to forward to your observability stack (Datadog, Prometheus, etc.).\n\n## Compatibility\n\n- Go `1.22+`\n- google.golang.org/grpc `v1.66+`\n- google.golang.org/protobuf `v1.36+`\n\nThe proto file is at [proto/pricing.proto](proto/pricing.proto). Generated `.pb.go` files are checked in, so you do not need `protoc` to build this project — only to regenerate after changing the proto.\n\n## Development\n\n```bash\ngo vet ./...\ngo test -race -v ./...\ngo build ./...\n```\n\nTests use `bufconn` to stand up the primary and candidate gRPC servers in-process. No network required.\n\n## License\n\nAGPL-3.0.\n\n---\n\n**Connect:** [LinkedIn](https://www.linkedin.com/in/mirzacausevic/) · [Kinetic Gain](https://kineticgain.com) · [Medium](https://medium.com/@mizcausevic/) · [Skills](https://mizcausevic.com/skills/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmizcausevic-dev%2Fgrpc-mesh-shadow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmizcausevic-dev%2Fgrpc-mesh-shadow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmizcausevic-dev%2Fgrpc-mesh-shadow/lists"}