gRPC は型の強い RPC を色々な言語を使って実装できる仕組みとライブラリです。
Big Sky :: Protocol Buffers を利用した RPC、gRPC を golang から試してみた。
grpc/grpc · GitHub gRPC - An RPC library and framework https://github.com/grpc/grpc gRPC は Google が開...
https://mattn.kaoriya.net/software/lang/go/20150227144125.htm
とても便利なのですが幾分手数が多いのが難点で、ちょっとしたサービスを gRPC で実装したいと思っていてもそう簡単に作る事が出来ませんでした。
ところが今回ご紹介する lile を使うと、とても簡単に gRPC を使った golang の実装を作れてしまいます。
GitHub - lileio/lile: Easily create gRPC services in Go
readme.md ALPHA: Lile is currently considered "Alpha" in that things may change. Currently I am gath...
https://github.com/lileio/lile
lile は gRPC のスケルトンを生成するコマンドとライブラリセットです。今日はこれを使って簡単に gRPC のサービスを作ってみます。お題は GENE95 辞書 を gRPC 経由で照会するサービスです。
まず lile をインストールするには以下のコマンドを実行します。
$ go get github.com/lileio/lile/...
Windows の人は今 pull-request を作ってるのでそちらを使って下さい。執筆時点でまだマージされてませんが。
lile をインストールしたらまずスケルトンを生成します。
$ lile new gene9go
Creating project in /home/mattn/go/src/github.com/mattn/lile-example/gene9go
Is this OK? [y]es/[n]o
yes
.
├── server
│ ├── server.go
│ └── server_test.go
├── subscribers
│ └── subscribers.go
├── gene9go
│ ├── cmd
│ ├── root.go
│ ├── serve.go
│ ├── subscribe.go
│ └── up.go
│ └── main.go
├── gene9go.proto
├── Makefile
├── Dockerfile
├── .travis.yml
└── .gitignore
git push できるくらいの物が生成されています。次に proto ファイルを編集して独自のインタフェースを作成します。元の proto ファイルは以下の様になっています。
syntax = "proto3";
option go_package = "github.com/mattn/lile-example/gene9go";
package gene9go;
message Request {
string id = 1;
}
message Response {
string id = 1;
}
service Gene9go {
rpc Read (Request) returns (Response) {}
}
これを以下の様に編集しました。
syntax = "proto3";
option go_package = "github.com/mattn/lile-example/gene9go";
package gene9go;
message Request {
string Word = 1;
}
message Response {
string Text = 1;
}
service Gene9go {
rpc Translate (Request) returns (Response) {}
}
辞書引きなので Translate メソッドを追加しています。編集し終えたら Makefile のある場所で make を実行します。するとこの proto ファイルから Translate メソッドのスケルトンが生成されます。
package server
import (
"errors"
"github.com/mattn/lile-example/gene9go"
context "golang.org/x/net/context"
)
func (s Gene9goServer) Translate(ctx context.Context, r *gene9go.Request) (*gene9go.Response, error) {
return nil, errors.New("not yet implemented")
}
尚、この時点でテストコードのスタブも生成されます。とても便利です。
package server
import (
"testing"
"github.com/mattn/lile-example/gene9go"
"github.com/stretchr/testify/assert"
context "golang.org/x/net/context"
)
func TestTranslate(t *testing.T) {
ctx := context.Background()
req := &gene9go.Request{}
res, err := cli.Translate(ctx, req)
assert.Nil(t, err)
assert.NotNil(t, res)
}
さてでは Translate メソッドの中身を実装します。gene.txt ファイルを読み込んで単語にマッチする次の行を返しているだけです。gene.txt は utf-8 で保存しておいて下さい。
package server
import (
"bufio"
"os"
"strings"
"github.com/mattn/lile-example/gene9go"
context "golang.org/x/net/context"
)
func translate(word string) (string, error) {
f, err := os.Open("gene.txt")
if err != nil {
return "", err
}
defer f.Close()
scanner := bufio.NewScanner(f)
found := ""
for scanner.Scan() {
first := scanner.Text()
if !scanner.Scan() {
break
}
if strings.ToLower(first) == strings.ToLower(word) {
found = scanner.Text()
break
}
}
return found, scanner.Err()
}
func (s Gene9goServer) Translate(ctx context.Context, r *gene9go.Request) (*gene9go.Response, error) {
text, err := translate(r.GetWord())
if err != nil {
return nil, err
}
return &gene9go.Response{Text: text}, nil
}
あとはクライアントとサーバを作ります。といっても Register 関数が用意されているのでこちらも簡単。まずはサーバ。
package main
import (
"log"
"net"
"github.com/mattn/lile-example/gene9go"
"github.com/mattn/lile-example/gene9go/server"
"google.golang.org/grpc"
)
func main() {
lis, err := net.Listen("tcp", ":11111")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
srv := grpc.NewServer()
gene9go.RegisterGene9goServer(srv, &server.Gene9goServer{})
srv.Serve(lis)
}
そしてクライアント。
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/mattn/lile-example/gene9go"
"google.golang.org/grpc"
)
func main() {
conn, err := grpc.Dial("localhost:11111", grpc.WithInsecure())
if err != nil {
log.Fatal(err)
}
defer conn.Close()
client := gene9go.NewGene9goClient(conn)
req := &gene9go.Request{
Word: os.Args[1],
}
resp, err := client.Translate(context.Background(), req)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Text)
}
後から気付いたのですが、gene9go の下にサーバコマンドも生成されてました。いたれりつくせり過ぎる。
A gRPC based service
Usage:
gene9go [command]
Available Commands:
help Help about any command
serve Run the RPC server
subscribe Subscribe to and process queue messages
up up runs both RPC and pubub subscribers
Flags:
-h, --help help for gene9go
Use "gene9go [command] --help" for more information about a command.
これだけです。なにこれ超簡単じゃん。サーバを起動した状態で、クライアントに単語を付けて起動します。
$ client Go
1.〜に進行する,行く,をしに行く,動く,過ぎる,至る,及ぶ,2.〜と書いてある
これを実装するのにわずか20分程度しか掛かりませんでした。今まで gRPC を使ったサービスに興味があったけど実装難しいと思っていた方はぜひ lile を使ってみて下さい。あっと言う間に実装できるはずです。
この記事で作ったソースファイルは以下に置いておきます。
GitHub - mattn/lile-example
https://github.com/mattn/lile-example