1package etcdv3
2
3import (
4	"context"
5	"io"
6	"time"
7
8	"github.com/go-kit/kit/endpoint"
9	"github.com/go-kit/kit/log"
10	"github.com/go-kit/kit/sd"
11	"github.com/go-kit/kit/sd/lb"
12	"google.golang.org/grpc"
13)
14
15func Example() {
16	// Let's say this is a service that means to register itself.
17	// First, we will set up some context.
18	var (
19		etcdServer = "10.0.0.1:2379"      // in the change from v2 to v3, the schema is no longer necessary if connecting directly to an etcd v3 instance
20		prefix     = "/services/foosvc/"  // known at compile time
21		instance   = "1.2.3.4:8080"       // taken from runtime or platform, somehow
22		key        = prefix + instance    // should be globally unique
23		value      = "http://" + instance // based on our transport
24		ctx        = context.Background()
25	)
26
27	options := ClientOptions{
28		// Path to trusted ca file
29		CACert: "",
30
31		// Path to certificate
32		Cert: "",
33
34		// Path to private key
35		Key: "",
36
37		// Username if required
38		Username: "",
39
40		// Password if required
41		Password: "",
42
43		// If DialTimeout is 0, it defaults to 3s
44		DialTimeout: time.Second * 3,
45
46		// If DialKeepAlive is 0, it defaults to 3s
47		DialKeepAlive: time.Second * 3,
48
49		// If passing `grpc.WithBlock`, dial connection will block until success.
50		DialOptions: []grpc.DialOption{grpc.WithBlock()},
51	}
52
53	// Build the client.
54	client, err := NewClient(ctx, []string{etcdServer}, options)
55	if err != nil {
56		panic(err)
57	}
58
59	// Build the registrar.
60	registrar := NewRegistrar(client, Service{
61		Key:   key,
62		Value: value,
63	}, log.NewNopLogger())
64
65	// Register our instance.
66	registrar.Register()
67
68	// At the end of our service lifecycle, for example at the end of func main,
69	// we should make sure to deregister ourselves. This is important! Don't
70	// accidentally skip this step by invoking a log.Fatal or os.Exit in the
71	// interim, which bypasses the defer stack.
72	defer registrar.Deregister()
73
74	// It's likely that we'll also want to connect to other services and call
75	// their methods. We can build an Instancer to listen for changes from etcd,
76	// create Endpointer, wrap it with a load-balancer to pick a single
77	// endpoint, and finally wrap it with a retry strategy to get something that
78	// can be used as an endpoint directly.
79	barPrefix := "/services/barsvc"
80	logger := log.NewNopLogger()
81	instancer, err := NewInstancer(client, barPrefix, logger)
82	if err != nil {
83		panic(err)
84	}
85	endpointer := sd.NewEndpointer(instancer, barFactory, logger)
86	balancer := lb.NewRoundRobin(endpointer)
87	retry := lb.Retry(3, 3*time.Second, balancer)
88
89	// And now retry can be used like any other endpoint.
90	req := struct{}{}
91	if _, err = retry(ctx, req); err != nil {
92		panic(err)
93	}
94}
95
96func barFactory(string) (endpoint.Endpoint, io.Closer, error) { return endpoint.Nop, nil, nil }
97