2017-01-12 28 views
6

Znalazłem interesujący problem, a mianowicie, że db.Ping() nie zwraca błędu, nawet jeśli baza danych została zabita od czasu pierwszej próby.Golang: Ping powiedzie się po raz drugi, nawet jeśli baza danych jest wyłączona

kod źródłowy poniżej:

import (
    "database/sql" 
    "fmt" 
    "log" 
    "time" 

    _ "github.com/go-sql-driver/mysql" 
) 

type database struct { 
    datasource string 
    conn  *sql.DB 
} 

// Connect creates and initialises a Database struct 
func (db *database) Connect(server, user, password, DBPort string) error { 
    var err error 

    db.datasource = fmt.Sprintf("%s:%[email protected]/", user, password) 
    db.conn, err = sql.Open(server, db.datasource) 
    if err != nil { 
     log.Fatal(err) 
    } 

    err = db.conn.Ping() 
    if err != nil { 
     db.conn.Close() 
     return err 
    } 

    log.Println("Waiting for 15 seconds, kill the DB") 
    <-time.After(15 * time.Second) 

    err = db.conn.Ping() 
    if err != nil { 
     db.conn.Close() 
     return err 
    } 

    log.Println("Second ping successful") 

    return nil 
} 

Początkowo baza danych jest w górę, więc pierwszy ping. Opóźniłem go jednak tylko ze względu na testy. W tym 15 sekund zatrzymuję bazę danych (sudo service mysql stop), jednak db.Ping() nadal się powiedzie.

Jeśli miałbym wykonać jakiekolwiek rzeczywiste zapytanie (przez db.Query, db.QueryRow lub db.Exec), to pakiet sql wpadłby w panikę z Broken Pipe (która jest oczekiwana).

Czy robię coś nie tak?

też: iść wersja go1.7.1 Linux/AMD64

Dzięki z góry!

Odpowiedz

9

Ping, po pierwszym połączeniu, w rzeczywistości ping bazy danych. To dziwne i złe, ale tak to działa (do Go 1.8). Jeśli w puli połączeń istnieje istniejące połączenie, które nie przekroczyło limitu czasu, Ping po prostu usunie go z puli i zwróci do ciebie, nie zadając sobie trudu sprawdzenia, czy baza danych nadal tam jest.

Kardianos (który napisał wyżej powiązany dokument, a także Govendor) naprawił to w wersji 1.8, pod warunkiem, że sterownik bazy danych go obsługuje. Do tego czasu jednak Ping nie jest wiarygodny w określaniu, czy baza danych nadal istnieje.

+0

Dzięki za szybką odpowiedź! Czy zdajesz sobie sprawę, w jaki sposób mogę sprawdzić, czy baza danych nadal działa? –

+1

Jedyny sposób, w jaki mogę teraz myśleć, to uruchomienie kwerendy typu "no-op" (np. 'SELECT WHERE 1 = 0') w stosunku do DB i zobaczenie, czy to panika (przez' odzyskać() '). To lub otwarcie drugiego połączenia z bazą danych, a następnie jej zamknięcie (co tylko potwierdza, że ​​baza danych nadal istnieje i jest dostępna, a nie że oryginalne połączenie jest nadal funkcjonalne). – Kaedys

+1

Dzięki jeszcze raz! Poszedłem z zastąpieniem drugiej 'Ping()' moją własną metodą "Alive()", która próbuje uruchomić kwerendę podobną do tej, którą udostępniłeś, odzyskuje od paniki, jeśli tak się stanie i zwraca błąd. W ten sposób serwer pozostaje w górze i może zgłosić, że baza danych jest tymczasowo niedostępna. Pozdrawiam! –