A client-side gRPC channel implementation for tonic

Overview

ginepro

ginepro provides client-side gRPC load-balancing out of the box by enriching tonic ‘s channel with periodic service discovery.

Crates.io Docs.rs CI Coverage Status

Overview

ginepro enriches tonic by periodcally updating the list of servers that are available through a ServiceDiscovery interface that currently is implemented for DNS.

How to install

Add ginepro to your dependencies

[dependencies]
# ...
ginepro = "0.1.0"

Getting started

The interface remains fairly the same as we implement all the logic for a drop-in replacement for tonic's Channel.

// Using the `LoadBalancedChannel`.
use ginepro::LoadBalancedChannel;
use ginepro::pb::tester_client::TesterClient;

// Build a load-balanced channel given a service name and a port.
let load_balanced_channel = LoadBalancedChannel::builder(
    ("my_hostname", 5000)
  )
  .await
  .expect("Failed to initialise the DNS resolver.")
  .channel();

// Initialise a new gRPC client for the `Test` service
// using the load-balanced channel as transport
let grpc_client = TesterClient::new(load_balanced_channel);

For more examples, have a look at the examples directory.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Comments
  • Upgrade tonic to 0.7

    Upgrade tonic to 0.7

    Upgrade tonic to 0.7

    This is a breaking change

    TODO: ~~They've made it harder to break TLS so for now I've just commented out the test that uses that feature. Probably for the best this way~~

    I've deleted these tests. We should find a way to test them properly at some point but for now I think it's fine

    opened by conradludgate 2
  • update tonic/prost and prepare for 0.3.0 release

    update tonic/prost and prepare for 0.3.0 release

    This PR does the following: Adds changelog for 0.3.0 release. Updates tonic to 0.6 and prost to 0.9. Removes blip comment . Updates to rust 2021 edition

    opened by tl-helge-hoff 2
  • move openssl to dev-dependencies

    move openssl to dev-dependencies

    Move openssl crate to dev-dependencis so that it does not introduce an unnecessary OpenSSL dependency for projects that do not need or want it; for example, projects that use RustTLS over OpenSSL.

    opened by tdyas 1
  • Add hostname verification and try to resolve ips on build.

    Add hostname verification and try to resolve ips on build.

    This PR tries to address the following:

    • Make sure that the hostname part of the ServiceDefinition is valid by making the fields private and force constructing it through from_parts that includes the validation.
    • Allow users to resolve the ServiceDefinition once before building the LoadBalancedChannel through a new method build_and_resolve that does the same as channel only that it will only succeed if a call to LookupService::resolve_service_endpoints is successful.

    Closes #20.

    opened by tl-helge-hoff 0
  • wait for an initial resolution to succeed before fully constructing `LoadBalancedChannel`

    wait for an initial resolution to succeed before fully constructing `LoadBalancedChannel`

    Motivations

    The service probe loop appears to log and ignore errors while running. This seems fine while the service is running, but at startup, it could be an indication that the ServiceDefinition has an invalid hostname (e.g., has a typo). Some callers might prefer to panic in that situation so deployment systems are immediately aware of a problem instead of just reporting nothing resolved via metrics.

    Solution

    When constructing a LoadBalancedChannel, the code should wait for an initial resolution of the provided ServiceDefinition to succeed before returning the LoadBalancedChannel. This has the benefit of (1) finding invalid DNS names immediately (and allowing the program to exit immediately); and (2) ensures that LoadBalancedChannel has an initial non-empty set of endpoints to use before the program enters application code.

    Alternatives

    An alternative would be for callers to access the current set of endpoints and wait with a timeout until there are one or more endpoints. If no endpoints are resolved by the timeout, then a caller could error exit or alert. I don't know offhand whether Channel supports something like this.

    enhancement 
    opened by tdyas 0
  • RUSTSEC-2021-0073: Conversion from `prost_types::Timestamp` to `SystemTime` can cause an overflow and panic

    RUSTSEC-2021-0073: Conversion from `prost_types::Timestamp` to `SystemTime` can cause an overflow and panic

    Conversion from prost_types::Timestamp to SystemTime can cause an overflow and panic

    | Details | | | ------------------- | ---------------------------------------------- | | Package | prost-types | | Version | 0.7.0 | | URL | https://github.com/tokio-rs/prost/issues/438 | | Date | 2021-07-08 | | Patched versions | >=0.8.0 |

    Affected versions of this crate contained a bug in which untrusted input could cause an overflow and panic when converting a Timestamp to SystemTime.

    It is recommended to upgrade to prost-types v0.8 and switch the usage of From<Timestamp> for SystemTime to TryFrom<Timestamp> for SystemTime.

    See #438 for more information.

    See advisory page for additional details.

    opened by github-actions[bot] 0
  • feat: new LoadBalancedChannelBuilder with LookupService

    feat: new LoadBalancedChannelBuilder with LookupService

    Our ServiceDefinition cannot be processed by DnsResolver, so LoadBalancedChannelBuilder::new_with_service will always a Err and cannot apply lookup_service later.

    opened by flisky 0
  • Implement `tower::Service` rather than `tonic::GrpcService`.

    Implement `tower::Service` rather than `tonic::GrpcService`.

    It allows LoadBalancedChannel to leverage all tower's external machinery (e.g. ServiceExt) and, thanks to tonic, we get a tonic::GrpcService implementation for free [not a breaking change, thanks to that].

    opened by LukeMathWalker 0
  • `LoadBalancedChannel::builder`

    `LoadBalancedChannel::builder`

    Add a builder method to allow users to ignore the LoadBalancedChannelBuilder type (or, at least, not having to import it directly). Edit examples to use the new method (and shorten them to avoid a horizontal scrollbar on docs.rs).

    opened by LukeMathWalker 0
  • Connection timeouts

    Connection timeouts

    Bug description

    Symptoms

    1. GRPC requests are taking too long to time out when Kubernetes network policies are misconfigured.
    2. The connection_timeout_is_not_fatal test takes ~75 seconds to finish.

    Well-configured timeouts are important for system stability. Requests which take too long can hog resources and block other work from happening.

    Causes

    I can see two separate timeout problems:

    1. DNS resolution – when ResolutionStrategy::Lazy is used, there is currently no way to apply a timeout just for DNS resolution. If DNS never resolves, requests never complete.
    2. TCP connection – there is currently no way to set a connection timeout. On my machine, the socket seems to time out after ~75s. Even when we do set a connection timeout, tonic doesn't use it!

    To Reproduce

    For the TCP connection timeout, just run the tests. I'll supply a test for lazy DNS resolution timeouts in a separate PR.

    Expected behavior

    Ability to control timeouts for TCP connections and DNS resolution.

    Environment

    • OS: MacOS
    • Rust version: rustc 1.65.0 (897e37553 2022-11-02)

    Additional context

    Solutions

    The TCP connection timeout is simpler to solve (though I will admit took me a long time to find): we just need to set connect_timeout in the right places. First, topic doesn't respect connect_timeout, which will be fixed by this PR. When that is merged, we can create our own connect_timeout option on top of it (PR incoming).

    DNS resolution is harder. There are currently two options:

    1. Lazy resolution seems to be the default, but it also seems very hard to put a timeout around (at least, I can't think of a way!). It's possible to put an overall timeout around every request in the application, but this is 1. overly broad and 2. error-prone. It's very easy to forget or simply not know that it's needed ("why don't the other timeouts take care of it?").
    2. Eager resolution has a timeout option. In practice, using this will probably mean doing DNS resolution on service startup, when the LoadBalancedChannel is created. This might be a good thing, preventing services from successfully starting when DNS would never resolve.

    Of the two, I think we should favour Eager resolution, and consider changing the default to this.

    However, we might want a third option: Active lazy resolution (for want of a better name). Lazy resolution is currently passive, as in it happens in the background on a schedule. It is never actively called in the request flow, which is why it's hard to put a timeout around. Instead, could we implement something which actively calls probe_once() (with a timeout!) as part of the first request (or alternatively when GrpcServiceProbe.endpoints is empty)? This could give us lazy DNS resolution, but with timeouts.

    bug 
    opened by ThomWright 0
  • add endpoint middlewares

    add endpoint middlewares

    Addresses #31. Adds a new EndpointMiddleware trait and adds the with_endpoint_layer method to the LoadBalancedChannelBuilder. These middlewares are invoked on every SocketAddr that the lookup service discovers.

    Usage:

    let load_balanced_channel = LoadBalancedChannel::builder(("www.test.com", 5000))
            // set the concurrency limit for the endpoint
            .with_endpoint_layer(|endpoint: Endpoint| Some(endpoint.concurrency_limit(1)))
            // set the user agent for the endpoint
            .with_endpoint_layer(|endpoint: Endpoint| {
                endpoint.user_agent("my ginepro client").ok()
            })
            .channel()
            .await
            .unwrap();
    
    opened by conradludgate 0
  • Consider means of configuring Endpoints

    Consider means of configuring Endpoints

    Motivations

    tonic's Endpoint type has many configurable parameters, for example keep_alive_interval

    ginepro internally constructs Endpoint instances from socket addresses, and then applies some limited configuration values (like tls and timeout), but otherwise most settings remain the default.

    Solution

    It's probably not practical or ergonomic to specify every configuration value in ginepro's API; however it would be useful if the library could accept something like a Fn(SocketAddr) -> Result<Endpoint, SomeError> so that the user could configure an endpoint while the library handles stuff like periodic dns lookups

    enhancement 
    opened by rnarubin 0
Owner
TrueLayer
Simple & Secure Bank APIs
TrueLayer
A customisable client for Discord rich presence using simple Lua configuration.

Installation | Usage | Configuration | Example Disco Disco is a customisable client for Discord rich presence using simple Lua configuration. Installa

KaitlynEthylia 5 Aug 7, 2023
Rust implementation to simply convert between coordinate systems

GeoMorph Simple conversion between different coordinate systems without external wrappers

Victor Lopes 10 Nov 8, 2022
A toy re-implementation of GNU Grep by Rust.

Mini Grep Mini Grep is a simple rust re-implementation of GNU Grep, which means it could just implement limited functions, such as searching specific

PeterWrght 1 Jul 15, 2022
Easy c̵̰͠r̵̛̠ö̴̪s̶̩̒s̵̭̀-t̶̲͝h̶̯̚r̵̺͐e̷̖̽ḁ̴̍d̶̖̔ ȓ̵͙ė̶͎ḟ̴͙e̸̖͛r̶̖͗ë̶̱́ṉ̵̒ĉ̷̥e̷͚̍ s̷̹͌h̷̲̉a̵̭͋r̷̫̊ḭ̵̊n̷̬͂g̵̦̃ f̶̻̊ơ̵̜ṟ̸̈́ R̵̞̋ù̵̺s̷̖̅ţ̸͗!̸̼͋

Rust S̵̓i̸̓n̵̉ I̴n̴f̶e̸r̵n̷a̴l mutability! Howdy, friendly Rust developer! Ever had a value get m̵̯̅ð̶͊v̴̮̾ê̴̼͘d away right under your nose just when

null 294 Dec 23, 2022
Fuzzer to automatically find side-channel (timing) vulnerabilities

SideFuzz: Fuzzing for side-channel vulnerabilities SideFuzz is an adaptive fuzzer that uses a genetic-algorithm optimizer in combination with t-statis

PHAYES 94 Sep 29, 2022
Fuzzer to automatically find side-channel (timing) vulnerabilities

SideFuzz: Fuzzing for side-channel vulnerabilities SideFuzz is an adaptive fuzzer that uses a genetic-algorithm optimizer in combination with t-statis

Patrick Hayes 94 Sep 29, 2022
ARM TrustZone-M example application in Rust, both secure world side and non-secure world side

ARM TrustZone-M example application in Rust, both secure world side and non-secure world side; projects are modified from generated result of cortex-m-quickstart.

null 44 Dec 4, 2022
Authorization Server with Rust using Tonic

authorization-server Authorization Server with Rust using Tonic. Function implemented User registration and profile store Change password Login Token

sora 3 Oct 5, 2021
Async variant of Tonic's `interceptor` function

Tonic Async Interceptor This crate contains AsyncInterceptor, an async variant of Tonic's Interceptor. Other than accepting an async interceptor funct

Arcanyx Technical Wizardry LLC 4 Dec 20, 2022
Rate Limiting middleware for Tower/Axum/Tonic/Hyper utilizing the governor crate

A Tower service and layer that provides a rate-limiting backend by governor. Based heavily on the work done for actix-governor. Works with Axum, Hyper

Ben Wishovich 31 Feb 15, 2023
This is an implementation defining standard for client-side-validation

Client-side-validation Foundation Libraries This is an implementation defining standard of client-side-validation representing a set of its Foundation

LNP/BP Association 8 Dec 3, 2022
Rust client-side implementation of the rock usb protocol

Utility crates to interact with Rockchip devices Rockchip SoCs implement a custom USB protocol when starting in a special recovery mode (sometimes cal

Collabora 12 Mar 14, 2023
Simple project to test grpc between ruby (client) and rust (server)

grpc-example Simple project to test grpc between ruby (client) and rust (server). Usage To simplify a lot this project uses docker and docker compose

Bruno Arueira 2 Oct 14, 2021
gRPC client/server for zero-knowledge proof authentication Chaum Pederson Zero-Knowledge Proof in Rust

gRPC client/server for zero-knowledge proof authentication Chaum Pederson Zero-Knowledge Proof in Rust. Chaum Pederson is a zero-knowledge proof proto

Advaita Saha 4 Jun 12, 2023
🦀 Rust-based implementation of a Snowflake Generator which communicates using gRPC

Clawflake Clawflake is a Rust application which implements Twitter Snowflakes and communicates using gRPC. Snowflake ID numbers are 63 bits integers s

n1c00o 5 Oct 31, 2022
An implementation of the ZITADEL gRPC API in Rust.

An implementation of the ZITADEL gRPC API in Rust. Complemented with other useful elements such as ServiceAccount auth.

Christoph Bühler 10 Dec 15, 2022
CouchDB client-side library for the Rust programming language

Chill Chill is a client-side CouchDB library for the Rust programming language, available on crates.io. It targets Rust Stable. Chill's three chief de

null 35 Jun 26, 2022
Everyday-use client-side map-aware Arch Linux mirror ranking tool

Rate Arch Mirrors This is a tool, which fetches mirrors, skips outdated/syncing Arch Linux mirrors, then uses info about submarine cables and internet

Nikita Almakov 196 Jan 2, 2023
Network-agnostic, high-level game networking library for client-side prediction and server reconciliation.

WARNING: This crate currently depends on nightly rust unstable and incomplete features. crystalorb Network-agnostic, high-level game networking librar

Ernest Wong 175 Dec 31, 2022
A Rust CLI tool that helps you enforce Git policies through Git hooks both server and client side

GitPolicyEnforcer This is a command line utility written in Rust, that helps you utilize Git hooks, to enforce various policies. It currently supports

Vagelis Prokopiou 4 Aug 14, 2022