Skip to content

Instantly share code, notes, and snippets.

@linnv
Created December 20, 2019 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save linnv/dc372cce851cd34d30674e0f4ef55497 to your computer and use it in GitHub Desktop.
Save linnv/dc372cce851cd34d30674e0f4ef55497 to your computer and use it in GitHub Desktop.
package demo
import (
"context"
"log"
"math/rand"
"path"
"time"
clientv3 "github.com/coreos/etcd/clientv3"
"github.com/linnv/logx"
"go.etcd.io/etcd/clientv3/concurrency"
"go.etcd.io/etcd/pkg/transport"
)
type Elector struct {
cli *clientv3.Client
IsLeader bool `json:"IsLeader"`
Name string `json:"Name"`
}
func NewElector(name string) *Elector {
e := &Elector{
Name: name,
}
return e
}
func (e *Elector) Close() {
e.cli.Close()
}
func (e *Elector) Init() {
if e == nil {
return
}
sslDir := "/Users/jialinwu/go12/src/github.com/linnv/golang-practice/demos/etcdDemo/ssl"
tlsInfo := transport.TLSInfo{
CertFile: path.Join(sslDir, "kube-etcd-192-168-1-125.pem"),
KeyFile: path.Join(sslDir, "kube-etcd-192-168-1-125-key.pem"),
TrustedCAFile: path.Join(sslDir, "kube-ca.pem"),
}
tlsConfig, err := tlsInfo.ClientConfig()
if err != nil {
log.Fatal(err)
}
timeout := 5 * time.Second
endpoints := []string{"https://192.168.1.125:2379"}
cli, err := clientv3.New(clientv3.Config{
Endpoints: endpoints,
DialTimeout: timeout,
TLS: tlsConfig,
})
if err != nil {
panic(err.Error())
}
e.cli = cli
}
func (e *Elector) Run() {
defer e.Close()
cli := e.cli
s1, err := concurrency.NewSession(cli)
if err != nil {
log.Fatal(err)
}
defer s1.Close()
const KEY_MASTER = "/my-election/"
e1 := concurrency.NewElection(s1, KEY_MASTER)
ticker := time.NewTicker(time.Second * 3)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
exitSecond := time.Second * 60 * time.Duration((r.Uint32()%5 + 1))
logx.Debugf("%s exit in seconds: %+v\n", e.Name, exitSecond)
tickerExit := time.NewTicker(exitSecond)
for {
select {
case <-tickerExit.C:
logx.Debugfln("exit: %s", e.Name)
return
case <-ticker.C:
if e.IsLeader {
continue
}
logx.Debugfln("blocking until [%s] become master[leader]", e.Name)
if err := e1.Campaign(context.Background(), e.Name); err != nil {
logx.Debugf("e.Name:[%s] err %s\n", e.Name, err)
return
}
e.IsLeader = true
//do something as master
logx.Debugf("e.Name:[%s] is master\n", e.Name)
if err := e1.Campaign(context.Background(), e.Name); err != nil {
logx.Debugf("e.Name:[%s] err %s\n", e.Name, err)
return
}
logx.Debugfln("check elect again(no blocking) [%s] become master[leader]", e.Name)
}
}
}
func JustDemo() {
}
package demo
import (
"log"
"os"
"os/signal"
"strconv"
"syscall"
"testing"
)
func TestJustDemo(t *testing.T) {
for i := 0; i < 5; i++ {
e := NewElector("elector " + strconv.Itoa(i))
e.Init()
go e.Run()
}
sigChan := make(chan os.Signal, 2)
signal.Notify(sigChan, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGSTOP)
log.Print("use c-c to exit: \n")
<-sigChan
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment