systemctl status monitor
package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "sync"
    "time"

    "monitor/utils/slack"

    "gopkg.in/yaml.v2"
)

var config struct {
    Frequency int
    Urls      []string
}

type statusType struct {
    values map[string]int
    mux    sync.Mutex
}

var status = statusType{values: make(map[string]int)}

func (s *statusType) set(url string, value int) {
    s.mux.Lock()
    s.values[url] = value
    s.mux.Unlock()
}

func init() {
    data, err := ioutil.ReadFile("config.yaml")
    if err != nil {
        fmt.Printf("Invalid config: %s\n", err)
        os.Exit(0)
    }

    err = yaml.Unmarshal(data, &config)
    if err != nil {
        fmt.Printf("Invalid config: %s\n", err)
        os.Exit(0)
    }

    for _, url := range config.Urls {
        status.set(url, 200)
    }
}

func main() {
    ticker := time.NewTicker(time.Duration(config.Frequency) * time.Second)
    for _ = range ticker.C {
        for _, url := range config.Urls {
            go check(url)
        }
    }
}

func check(url string) {
    res, err := http.Get(url)
    if err != nil {
        res = &http.Response{StatusCode: 500}
    }

    // the memory problem occurs when this condition is never satisfied, so I didn't post the slack package.
    if res.StatusCode != status.values[url] {
        status.set(url, res.StatusCode)

        err := slack.Alert(url, res.StatusCode)
        if err != nil {
            fmt.Println(err)
        }
    }
}

如果这属于Code Review,那么我会把它放在那里.



1> Adrian..:

是的,这是内存泄漏.我可以发现一个明显的来源是你没有从你的请求中关闭响应主体:

func check(url string) {
    res, err := http.Get(url)
    if err != nil {
        res = &http.Response{StatusCode: 500}
    } else {
        defer res.Body.Close()    // You need to close the response body!
    }

    if res.StatusCode != status.values[url] {
        status.set(url, res.StatusCode)

        err := slack.Alert(url, res.StatusCode)
        if err != nil {
            fmt.Println(err)
        }
    }
}

更好的是,所以Go可以使用keepalive,你想要阅读全身并关闭它:

defer func() {
    io.Copy(ioutil.Discard, res.Body)
    res.Body.Close()
}()
pprof