Golang периодический опрос серверов перестаёт работать

Программа пашет на протяжении нескольких минут, ломается и выдаёт ошибку. Код ошибки:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x50 pc=0x5d8063]

goroutine 35 [running]:
main.getStatistics({0xc000190040, 0x9})
        C:/Program Files/xampp/server/server.go:71 +0xc3
created by main.main
        C:/Program Files/xampp/server/server.go:62 +0x3b9

Логика программы: 1) Получаем ip адреса всех устройств из mysql 2) В бесконечном цикле вызываем для каждого ip функцию и запускаем ее в горутине 3) В функции отсылаем по tcp всем устройствам набор байт и слушаем ответ 4) Из полученных данных собираем ответ и пишем в redis

func main() {
    db, err := sql.Open("mysql", "test:@/test")
    if err != nil {
        panic(err)
    }

    rows, err := db.Query("select * from inclunometers")
    if err != nil {
        panic(err)
    }

    inclunometers := []inclunometer{}
    for rows.Next() {
        p := inclunometer{}
        err := rows.Scan(&p.id, &p.Type, &p.accuracy, &p.ip, &p.rs485_address, &p.side_id)
        if err != nil {
            fmt.Println(err)
            continue
        }
        inclunometers = append(inclunometers, p)
    }

    defer rows.Close()
    defer db.Close()

    for _, element := range inclunometers {
        for {
            go getStatistics(element.ip)
            time.Sleep(500 * time.Millisecond)
        }
    }
}

Ранее вызывал эту функцию раз в 8 секунд и всё стабильно работало на протяжении как минимум нескольких дней, но появилась необходимость вызывать её два раза в секунду.

func getStatistics(ip string) {
    conn, _ := net.Dial("tcp", string(ip+":50"))

    _, err := conn.Write([]byte{0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0xC4, 0x0B})
    if err != nil {
        panic(err)
    }

    windSpeedStatistics := make([]byte, 10)
    message, _ := bufio.NewReader(conn).Read(windSpeedStatistics)
    if message == 0 {
        panic("can`t get wind stats")
    }
    windSpeed := (float64(binary.BigEndian.Uint16(windSpeedStatistics[3:5]) / 100))

    _, err = conn.Write([]byte{0x01, 0x03, 0x00, 0x01, 0x00, 0x02, 0x95, 0xCB})
    if err != nil {
        panic(err)
    }

    windDirection := make([]byte, 10)
    message, _ = bufio.NewReader(conn).Read(windDirection)
    if message == 0 {
        panic("can`t get wind stats")
    }
    direction := (float64(binary.BigEndian.Uint16(windDirection[3:5])) / 100)

    prepareJson := jsonStatistics{Date.Format("2006-01-02 15:04:05"), ip, direction, windSpeed}
    jsonDecode, err := json.Marshal(prepareJson)
    if err != nil {
        panic(err)
    }

    /*REDIS*/
    redisKey := "ip:" + ip
    currUnix := time.Now().Unix()
    redisConn, err := redis.Dial("tcp", "localhost:6379")
    if err != nil {
        panic(err)
    }

    v, err := redisConn.Do("ZADD", redisKey, int(currUnix), jsonDecode)
    if v == 0 || err != nil {
        panic(err)
    }
    /*REDIS*/

    defer conn.Close()
    defer redisConn.Close()
    return windSpeed, direction
}

Ответы (1 шт):

Автор решения: young_protokaa42

Проблема была решена внесением ряда изменений:

1) Ранее, в функции main для каждого устройства запускался бесконечный цикл. 
Теперь же в горутине вызывается отдельная функция.
2) Выяснилось, что функция не успевает отрабатывать два раза в секунду. 
Был убран её  периодический опрос. Теперь она снова запустится,
как только выполнится, отправив в callSurvey результат true.
3) В прошлой версии соединение tcp открывалось и закрывалось при каждом прохождении
функции опроса. Теперь соединение открывается в начале программы и так и висит открытым. 
Не знаю, насколько плохо держать соединение длительное время открытым,
но программа показывает хороший результат, бесперебойно работая уже как четверо суток.
for _, element := range inclunometers {
        go callSurvey(element.ip)
}

func callSurvey(ip string) {
    conn, err := net.Dial("tcp", string(ip+":50"))
    if err != nil {
        fmt.Println(time.Now(), err)
    }

    for {
        result := getStatistics(ip, conn)

    DELAY:
        time.Sleep(100 * time.Millisecond)
        if !result {
            goto DELAY
        }
    }
}

func getStatistics(ip string, conn net.Conn) bool {
    ...
    return true;
}
→ Ссылка