github.com/mailgun/holster/v4@v4.20.0/etcdutil/README.md (about)

     1  ## NewElection()
     2  Use etcd for leader election if you have several instances of a service running in production
     3  and you only want one of the service instances to preform a task.
     4  
     5  `LeaderElection` starts a goroutine which performs an election and maintains a leader
     6  while candidates join and leave the election. Calling `Close()` will concede leadership if
     7  the service currently has it and will withdraw the candidate from the election.
     8  
     9  ```go
    10  
    11  import (
    12      "github.com/mailgun/holster/v4/etcdutil"
    13  )
    14  
    15  func main() {
    16      var wg holster.WaitGroup
    17  
    18      client, err := etcdutil.NewClient(nil)
    19      if err != nil {
    20          fmt.Fprintf(os.Stderr, "while creating etcd client: %s\n", err)
    21          return
    22      }
    23      
    24  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
    25  	defer cancel()
    26  
    27      // Start a leader election and attempt to become leader, only returns after
    28      // determining the current leader.
    29  	election := etcdutil.NewElection(ctx, client, etcdutil.ElectionConfig{
    30  		Election:                "my-service",
    31  		Candidate:               "my-candidate",
    32  		EventObserver: func(e etcdutil.Event) {
    33  			leaderChan <- e
    34  			if e.IsDone {
    35  				close(leaderChan)
    36  			}
    37  		},
    38  		TTL: 10,
    39  	})
    40  
    41      // Handle graceful shutdown
    42      signalChan := make(chan os.Signal, 1)
    43      signal.Notify(signalChan, os.Interrupt, os.Kill)
    44  
    45      // Do periodic thing
    46      tick := time.NewTicker(time.Second * 2)
    47      wg.Loop(func() bool {
    48          select {
    49          case <-tick.C:
    50              // Are we currently leader?
    51              if election.IsLeader() {
    52                  err := DoThing()
    53                  if err != nil {
    54                      // Have another instance run DoThing()
    55                      // since we can't for some reason.
    56                      election.Concede()
    57                  }
    58              }
    59              return true
    60          case <-signalChan:
    61              election.Stop()
    62              return false
    63          }
    64      })
    65      wg.Wait()
    66      
    67      // Or you can pipe events to a channel
    68      for leader := range leaderChan {
    69      	fmt.Printf("Leader: %v\n", leader)
    70      }
    71  }
    72  ```
    73  
    74  ## NewConfig()
    75  Designed to be used in applications that share the same etcd config
    76  and wish to reuse the same config throughout the application.
    77  
    78  ```go
    79  import (
    80      "os"
    81      "fmt"
    82  
    83      "github.com/mailgun/holster/v4/etcdutil"
    84  )
    85  
    86  func main() {
    87      // These environment variables provided by the environment,
    88      // we set them here to only to illustrate how `NewConfig()`
    89      // uses the environment to create a new etcd config
    90      os.Setenv("ETCD3_USER", "root")
    91      os.Setenv("ETCD3_PASSWORD", "rootpw")
    92      os.Setenv("ETCD3_ENDPOINT", "etcd-n01:2379,etcd-n02:2379,etcd-n03:2379")
    93  
    94      // These default to /etc/mailgun/ssl/localhost/etcd-xxx.pem if the files exist
    95      os.Setenv("ETCD3_TLS_CERT", "/path/to/etcd-cert.pem")
    96      os.Setenv("ETCD3_TLS_KEY", "/path/to/etcd-key.pem")
    97      os.Setenv("ETCD3_CA", "/path/to/etcd-ca.pem")
    98      
    99      // Set this to force connecting with TLS, but without cert verification
   100      os.Setenv("ETCD3_SKIP_VERIFY", "true")
   101  
   102      // Create a new etc config from available environment variables
   103      cfg, err := etcdutil.NewConfig(nil)
   104      if err != nil {
   105          fmt.Fprintf(os.Stderr, "while creating etcd config: %s\n", err)
   106          return
   107      }
   108  }
   109  ```
   110  
   111  ## NewClient()
   112  Just like `NewConfig()` but returns a connected etcd client for use by the
   113  rest of the application.
   114  
   115  ```go
   116  import (
   117      "os"
   118      "fmt"
   119  
   120      "github.com/mailgun/holster/v4/etcdutil"
   121  )
   122  
   123  func main() {
   124      // Create a new etc client from available environment variables
   125      client, err := etcdutil.NewClient(nil)
   126      if err != nil {
   127          fmt.Fprintf(os.Stderr, "while creating etcd client: %s\n", err)
   128          return
   129      }
   130  
   131      // Use client
   132  }
   133  ```