如何在Golang中实现每5分钟调用REST API获取token的重试逻辑

cczfrluj  于 2023-11-14  发布在  Go
关注(0)|答案(2)|浏览(95)

我必须在Golang中每5分钟进行一次API调用来捕获响应。如何在Golang中实现每5分钟进行一次REST API调用以获取响应令牌的重试逻辑?

res, err := http.Get("https://mydadisjoke.com/Acct?")
    if err != nil {
        return "", err
    }   
    
    // defining a struct instance
    var KeyID Response
 
    // data in JSON format which
    // is to be decoded
    Data := []byte(`{
        "Key"                    :  "Key",
        "Account"                   :  "Account",
            }`)
 
    // decoding Response struct
    // from json format
    err := json.Unmarshal(Data, &KeyId)
 
    if err != nil {
        fmt.Println(err)
    }
 
    // printing details of
    // decoded data
    fmt.Println("Struct is:", KeyId)
    fmt.Printf("Key is %s\n", KeyId.Key)

字符串

hs1ihplo

hs1ihplo1#

你可以把上面的代码做成一个函数,并在外面加上时间控制:

// define function
func doHttpCall() error {
    // above code

    if err != nil {
        return err
    }
    return nil
}

// visit every 5min 
func main() {
    for {
        err := doHttpCall()
        if err != nil {
            fmt.Println("API call failed:", err)
        } else {
            fmt.Println("API call success")
        }

        time.Sleep(5 * time.Minute)
    }
}

字符串

eufgjt7s

eufgjt7s2#

您可以使用time.NewTicker(interval)
NewTicker返回一个新的Ticker,其中包含一个通道,该通道将在每次滴答之后发送通道上的当前时间。滴答的周期由duration参数指定。Ticker将调整时间间隔或丢弃滴答以弥补慢接收器。duration d必须大于零;否则,NewTicker将死机。停止Ticker以释放相关资源。
在这里,它将在第一次调用1秒后调用,然后调用5次。分钟后:

var interval = 1 * time.Second

func getPeriodically(ctx context.Context, wg *sync.WaitGroup) {
    defer wg.Done()

    t := time.NewTicker(interval)
    defer t.Stop()
    for {
        select {
        case <-t.C:
            interval = 5 * time.Minute
            t.Reset(interval)
            k, err := demo(ctx)
            if err != nil {
                slog.Error("get", "error", err.Error())
                break
            }
            slog.Info("get", "key", k)

        case <-ctx.Done():
            slog.Info("getPeriodically: graceful shutdown completed")
            return
        }
    }
}

字符串
完整示例:

package main

import (
    "context"
    "encoding/json"
    "log/slog"
    "net/http"
    "os"
    "os/signal"
    "runtime"
    "sync"
    "syscall"
    "time"
)

func main() {
    slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{AddSource: true})))
    slog.Info(runtime.Version())

    // Setup graceful shutdown
    signals := make(chan os.Signal, 1)
    // Docker and Kubernetes use the SIGTERM signal to gracefully shut down a container.
    signal.Notify(signals, os.Interrupt, syscall.SIGTERM)

    var wg sync.WaitGroup
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    withServer := len(os.Args) == 1
    if withServer {
        wg.Add(1)
        go serve(ctx, &wg)
    }

    wg.Add(1)
    go getPeriodically(ctx, &wg)

    // Wait for the termination signal
    v := <-signals
    slog.Info("Starting graceful shutdown", "Received termination signal", v)
    if withServer {
        err := server.Shutdown(ctx)
        if err != nil {
            slog.Error("server", "error", err)
        }
    }

    cancel()

    wg.Wait()
    slog.Info("App: graceful shutdown completed")
}

var interval = 1 * time.Second

func getPeriodically(ctx context.Context, wg *sync.WaitGroup) {
    defer wg.Done()

    t := time.NewTicker(interval)
    defer t.Stop()
    for {
        select {
        case <-t.C:
            interval = 5 * time.Minute
            t.Reset(interval)
            k, err := demo(ctx)
            if err != nil {
                slog.Error("get", "error", err.Error())
                break
            }
            slog.Info("get", "key", k)

        case <-ctx.Done():
            slog.Info("getPeriodically: graceful shutdown completed")
            return
        }
    }
}

var (
    address    = "http://127.0.0.1:8080/Acct"
    serverAddr = ":8080"
    client     = http.Client{
        Timeout: 10 * time.Second,
    }
    server *http.Server
)

func demo(ctx context.Context) (key string, err error) {
    get, err := http.NewRequestWithContext(ctx, http.MethodGet, address, nil)
    if err != nil {
        return
    }

    res, err := client.Do(get)
    if err != nil {
        return
    }
    defer res.Body.Close()

    var KeyId *Response
    err = json.NewDecoder(res.Body).Decode(&KeyId)
    if err != nil {
        return
    }

    key = KeyId.Key
    return
}

type Response struct {
    Key string
}

func serve(ctx context.Context, wg *sync.WaitGroup) {
    defer wg.Done()
    mux := http.NewServeMux()
    mux.HandleFunc("/Acct", home)

    // Create a custom HTTP server with read and write timeouts
    server = &http.Server{
        Addr:         serverAddr,
        Handler:      mux,
        ReadTimeout:  10 * time.Second, // Set read timeout to 10 seconds
        WriteTimeout: 10 * time.Second, // Set write timeout to 10 seconds
    }

    slog.Info("Server", "Addr", server.Addr)
    err := server.ListenAndServe()
    if err != nil && err != http.ErrServerClosed {
        slog.Error("Server", "error", err)
        panic(err)
    }
    slog.Info("Server: graceful shutdown completed")
}

func home(w http.ResponseWriter, r *http.Request) {
    userIP := r.Header.Get("X-Forwarded-For")
    if userIP == "" {
        userIP = r.RemoteAddr
    }
    slog.Info("server", "userIP", userIP)
    Data := []byte(`{ "Key":  "Key1234", "Account":  "Account1234" }`)
    w.Write(Data)
}

相关问题