github.com/nais/knorten@v0.0.0-20240104110906-55926958e361/pkg/leaderelection/leaderelection.go (about)

     1  package leaderelection
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"net/http"
     8  	"os"
     9  	"time"
    10  )
    11  
    12  func IsLeader() (bool, error) {
    13  	electorPath := os.Getenv("ELECTOR_PATH")
    14  	if electorPath == "" {
    15  		// local development
    16  		return true, nil
    17  	}
    18  
    19  	hostname, err := os.Hostname()
    20  	if err != nil {
    21  		return false, err
    22  	}
    23  
    24  	leader, err := getLeader(electorPath)
    25  	if err != nil {
    26  		return false, err
    27  	}
    28  
    29  	return hostname == leader, nil
    30  }
    31  
    32  func getLeader(electorPath string) (string, error) {
    33  	resp, err := electorRequestWithRetry(electorPath, 3)
    34  	if err != nil {
    35  		return "", err
    36  	}
    37  	defer resp.Body.Close()
    38  	bodyBytes, err := io.ReadAll(resp.Body)
    39  	if err != nil {
    40  		return "", err
    41  	}
    42  
    43  	var electorResponse struct {
    44  		Name string
    45  	}
    46  
    47  	if err := json.Unmarshal(bodyBytes, &electorResponse); err != nil {
    48  		return "", err
    49  	}
    50  
    51  	return electorResponse.Name, nil
    52  }
    53  
    54  func electorRequestWithRetry(electorPath string, numRetries int) (*http.Response, error) {
    55  	for i := 1; i <= numRetries; i++ {
    56  		resp, err := http.Get("http://" + electorPath)
    57  		if err == nil {
    58  			return resp, nil
    59  		}
    60  		time.Sleep(time.Second * time.Duration(i))
    61  	}
    62  
    63  	return nil, fmt.Errorf("no response from elector container after %v retries", numRetries)
    64  }