mtchuyen / Golang-Tips

Tips in Golang programming
3 stars 2 forks source link

func #9

Open mtchuyen opened 3 years ago

mtchuyen commented 3 years ago

Retry func

Solution 1

func retry(attempts int, sleep time.Duration, f func() error) (err error) {
    for i := 0; ; i++ {
        err = f()
        if err == nil {
            return
        }

        if i >= (attempts - 1) {
            break
        }

        time.Sleep(sleep)

        log.Println("retrying after error:", err)
    }
    return fmt.Errorf("after %d attempts, last error: %s", attempts, err)
}

Solution 2:

Source: https://github.com/core-go/mq

func NewRetryArray(retries []time.Duration) (error) {
    i := 0
    err := Retry(retries, func() (err error) {
        i = i + 1
        //activity
        r2, er2 := retryActivity()
        r = r2
        if er2 == nil {
            log.Println(fmt.Sprintf("retryActivity successfully after %d retries", i))
        }
        return er2
    })
    if err != nil {
        log.Println(fmt.Sprintf("Failed to after successfully %d retries", i))
    }
    return &r, err
}

func Retry(sleeps []time.Duration, f func() error) (err error) {
    attempts := len(sleeps)
    for i := 0; ; i++ {
        log.Printf("Retrying %d of %d ", i+1, attempts)
        err = f()
        if err == nil {
            return
        }
        if i >= (attempts - 1) {
            break
        }
        time.Sleep(sleeps[i])
        log.Printf("Retrying %d of %d after error: %s", i+1, attempts, err.Error())
    }
    return fmt.Errorf("after %d attempts, last error: %s", attempts, err)
}
mtchuyen commented 3 years ago
func MakeDurations(vs []int64) []time.Duration {
    durations := make([]time.Duration, 0)
    for _, v := range vs {
        d := time.Duration(v) * time.Second
        durations = append(durations, d)
    }
    return durations
}
mtchuyen commented 3 years ago

Defer func

https://itnext.io/the-power-of-golang-keyword-defer-b31bdecf10b6

Chỉ dẫn defer được tạo ra để giải quyết các vấn đề:

Dùng defer khi nào

Dùng defer đúng cách

1. The program terminates immediately; deferred functions are not run.

program terminates immediately có thể là: os.Exit(), log.Fatal/log.Fatalf.

mtchuyen commented 2 years ago

Use Function as Values in Go

https://betterprogramming.pub/3-different-ways-to-use-function-as-values-in-go-6e4bbcdba4c3

mtchuyen commented 1 year ago

Error

https://groups.google.com/g/golang-nuts/c/vrMYqiLJqIE

package main

import (
    "errors"
    "fmt"
)

type someError struct {
    error
    isNotFound bool
}

func main() {
    var ErrNotFound error = &someError{error: errors.New("key not found"), isNotFound: true}
    var e error = &someError{error: errors.New("key not found"), isNotFound: true}
    fmt.Println(e == ErrNotFound)
    fmt.Printf("%T %V\n", e, e)
    fmt.Printf("%T %V\n", ErrNotFound, ErrNotFound)
    fmt.Println()
}

==> Khi chạy thì dòng này fmt.Println(e == ErrNotFound) return false (giá trị mong muốn là true). Tác giả muốn so sánh (bằng phương pháp so sánh string) giá trị trả về của hàm Error để biết thuộc loại Error nào.

axel.wa reply:

Every invocation of errors.New returns a new unique error value, even if the same error text is used. That is intentional. It would be confusing, if package A chose the same error sentinel text as package B and suddenly their sentinels compare as equal. If you want error identity between values, you have to actually copy the error value (or implement your own, which may very well not do it this way).

To be clear: The recommendation is not to compare strings. The recommendation is to compare errors by identity and not consider errors created by different packages to be equal.

If you desperately need your error to be considered "the same" as another, the most correct way would be to implement Is(other error) bool, e.g.

type someError struct {
    str string
}

func (s someError) Error() string {
    return s.str
}

func main() {
    var (
        ErrNotFound error = &someError{str: "key not found"}
        e           error = &someError{str: "key not found"}

        ErrNotFoundValue error = someError{str: "key not found"}
        eValue                 = someError{str: "key not found"}
    )
    fmt.Println(e == ErrNotFound)
    fmt.Println(eValue == ErrNotFoundValue)
}