func main() { flag.Parse() ch, err := tchannel.NewChannel("ping", nil) if err != nil { log.Fatalf("channel did not create successfully: %v", err) } logger := log.StandardLogger() rp, err := ringpop.New("ping-app", ringpop.Channel(ch), ringpop.Identity(*hostport), ringpop.Logger(bark.NewLoggerFromLogrus(logger)), ) if err != nil { log.Fatalf("Unable to create Ringpop: %v", err) } worker := &worker{ channel: ch, ringpop: rp, logger: logger, } if err := worker.RegisterPong(); err != nil { log.Fatalf("could not register pong handler: %v", err) } if err := worker.channel.ListenAndServe(*hostport); err != nil { log.Fatalf("could not listen on given hostport: %v", err) } opts := new(swim.BootstrapOptions) opts.File = *hostfile if _, err := worker.ringpop.Bootstrap(opts); err != nil { log.Fatalf("ringpop bootstrap failed: %v", err) } select {} }
func main() { flag.Parse() channel, err := tchannel.NewChannel("pingpong", &tchannel.ChannelOptions{}) if err != nil { log.Fatalf("could not create channel: %v", err) } server := thrift.NewServer(channel) // The actual service implementation worker := newWorker(*hostport, channel) // wrap the PingPong worker by a ringpop adapter for routing RPC calls // NewRingpopPingPongAdapter is in the package containing the generated code // Its name is derived from the thrift service name as follows: `NewRingpop[Service Name]Adapter` adapter, err := gen.NewRingpopPingPongAdapter(worker, worker.ringpop, channel, // PingPongConfiguration contains the configuration for ringpop forwarding regaring this service // The name is derived as follows `[Service Name]Configuration` gen.PingPongConfiguration{ // The ping member of the configuration refers to the Ping endpoint within the service. // Configuring an endpoint is optional and unconfigured endpoints will work but not be // forwarded to a different ringpop node during invocation // The name of the configuration struct passed in here is derived as follows: // `[Service Name][Endpoint Name]Configuration` Ping: &gen.PingPongPingConfiguration{ // The configuration structs only member is the Key closure. The purpose of this closure // is to return the key used for ringpop sharding and forwarding. Calls that are sharded // on the same key are guaranteed to be forwarded to the same node. // The input signature for this closure is the same as the signature for your // implementation. The output is always the tuple (shardKey string, err error). Key: func(ctx thrift.Context, request *gen.Ping) (shardKey string, err error) { // The body of the Key closure can perform whatever logic is needed to come to a // meaningful shardKey for the the request if request == nil { return "", errors.New("missing request in call to Ping") } // Here we route the ping's for the same key to the same machine return request.Key, nil }, }, }, ) if err != nil { log.Fatalf("unable to wrap the worker: %q", err) } // now pass the ringpop adapter into the TChannel Thrift server for the PingPong Service server.Register(gen.NewTChanPingPongServer(adapter)) if err := channel.ListenAndServe(*hostport); err != nil { log.Fatalf("could not listen on hostport: %v", err) } bsopts := new(swim.BootstrapOptions) bsopts.File = *hostfile bsopts.Stopped = true if _, err := worker.ringpop.Bootstrap(bsopts); err != nil { log.Fatalf("could not bootstrap ringpop: %v", err) } // block select {} }