gRPC Elixir

Hex.pmBuild StatusInline docs

An Elixir implementation of gRPC.

WARNING: Be careful to use it in production! Test and benchmark in advance.

NOTICE: Erlang/OTP needs >= 20.3.2

Installation

The package can be installed as:

  def deps do
    [
      {:grpc, github: "elixir-grpc/grpc"},
      # This may be needed when grpc_{cowlib/gun/cowboy} packages on hex are used, see mix.exs for
      # details.
      # Also see below explain.
      {:cowlib, "~> 2.8.0", hex: :grpc_cowlib, override: true},
    ]
  end

NOTICE: grpc_gun & grpc_cowlib may be used

grpc rely on them heavily but I can't control the release of gun and cowlib. I don't want to always wait for their releases epecially when their HTTP/2 support are not very stable. And hex doesn't allow dependencies are GitHub, so I published my own versions to hex so that grpc can be published.

My current releases don't have big differences with the upstream ones. And I think this hack will only be used in the near future because cowlib, gun and cowboy are becoming more and more stable.

Usage

  1. Generate Elixir code from proto file as protobuf-elixir shows(especially the gRPC Support section).

  2. Implement the server side code like below and remember to return the expected message types.

    defmodule Helloworld.Greeter.Server do
    use GRPC.Server, service: Helloworld.Greeter.Service
    
    @spec say_hello(Helloworld.HelloRequest.t, GRPC.Server.Stream.t) :: Helloworld.HelloReply.t
    def say_hello(request, _stream) do
     Helloworld.HelloReply.new(message: "Hello #{request.name}")
    end
    end
  3. Start the server

You can start the gRPC server as a supervised process. First, add GRPC.Server.Supervisor to your supervision tree.

# Define your endpoint
defmodule Helloworld.Endpoint do
  use GRPC.Endpoint

  intercept GRPC.Logger.Server
  run Helloworld.Greeter.Server
end

# In the start function of your Application
defmodule HelloworldApp do
  use Application
  def start(_type, _args) do
    children = [
      # ...
      supervisor(GRPC.Server.Supervisor, [{Helloworld.Endpoint, 50051}])
    ]

    opts = [strategy: :one_for_one, name: YourApp]
    Supervisor.start_link(children, opts)
  end
end

Then start it when starting your application:

# config.exs
config :grpc, start_server: true

# test.exs
config :grpc, start_server: false

$ iex -S mix

or run grpc.server using a mix task

$ mix grpc.server
  1. Call rpc:
    iex> {:ok, channel} = GRPC.Stub.connect("localhost:50051")
    iex> request = Helloworld.HelloRequest.new(name: "grpc-elixir")
    iex> {:ok, reply} = channel |> Helloworld.Greeter.Stub.say_hello(request)
    
    # With interceptors
    iex> {:ok, channel} = GRPC.Stub.connect("localhost:50051", interceptors: [GRPC.Logger.Client])
    ...

Check examples and interop(Interoperability Test) for some examples.

TODO

Benchmark

  1. Simple benchmark by using ghz

  2. Benchmark followed by official spec

Sponsors

This project is being sponsored by Tubi. Thank you!

Contributing

You contributions are welcome!

Please open issues if you have questions, problems and ideas. You can create pull requests directly if you want to fix little bugs, add small features and so on. But you'd better use issues first if you want to add a big feature or change a lot of code.