Golang MongoDB connection 加 Ping 確認連線

最近在使用Golang 開發使用MongoDB的系統,MongoDB是一個目前非常流行的NO-SQL (Not Only -SQL)資料庫,網路上有很多的介紹了,這邊不多說,使用起來跟關聯式資料庫不太一樣,但由於其彈性及在某些應用情境下的高速,因此也就成了系統開發的一個不可或缺的資料庫選項。

使用MongoDB

在Golang下使用MongoDB並不特別,一樣是先取得好的Go MongoDB套件,如果有爬過一些文,會發現之前很多的部落客會推薦mgo,但是mgo已經停止維護更新了,好像停留在MongoDB v4.3 吧(目前v 7.0),因此建議使用官方推薦的mongo-driver,可以用以下命令取得:

go get go.mongodb.org/mongo-driver/mongo

取得後,如同一般使用資料庫/網路服務/序列服務一樣,先建立Client然後建立連線,mongo-driver新版兩者一次到位,如下(下例使用的是有帳號密碼的連線方式),後面跟著選擇資料庫(Database)、選擇Collection,然後正常使用查詢、CRUD等等。(由於是NO-SQL,跟一般的SQL不太一樣,需要學一下它的一些專門用法及Bson語法)。

package main

import (
	"context"
	"fmt"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
	credential := options.Credential{
		Username: "xxxx",
		Password: "bbbb",
	}
  
	clientOpts := options.Client().ApplyURI("mongodb://localhost:27017").SetAuth(credential)
	//clientOpts := options.Client().ApplyURI("mongodb://localhost:27017")  //沒有帳號密碼下直接連
	ctx := context.Background()
	client, err := mongo.Connect(ctx, clientOpts)
  	if err != nil {
    	fmt.Println(err) //Connect似乎不吐error
    	return
  	}
	
	//db
	db := client.Database("test")
	collectionNames, err := db.ListCollectionNames(ctx, bson.M{})
	fmt.Println("collectionNames:", collectionNames)

	//collection
	collection := db.Collection("member")
	fmt.Printf("collection: %s \n", collection.Name())
  
   //後續進行查詢、CRUD等

問題

以上一切很棒,使用起來如同預期,直到有一次我密碼輸入錯誤,奇怪,系統在連線時並未返回err,而是直接跑到查詢的時候panic了(導致系統crash),或是連到一個錯誤的位址,也是類似的情況,就好像mongo.Connect不會吐出error。

解法

使用client.Ping()如下,於Connect之後ping一下Server,Ping()在有錯誤的時候會回傳error,例如上述的帳密有錯、server not response等等,都會分別回傳錯誤。

	client, err := mongo.Connect(ctx, clientOpts)
	err = client.Ping(ctx, nil)    //若沒有成功連線,則會返回error
	if err != nil {
		fmt.Println(err)
		return
	}

原因

身為一個追根究柢的工程師,在能順利處理問題後我們還是想要了解一下原因是甚麼,參考套件中Connect的說明

The Client.Connect method starts background goroutines to monitor the state of the deployment and does not do any I/O in the main goroutine to prevent the main goroutine from blocking. Therefore, it will not error if the deployment is down.

也就是說Connect時並沒有真的去進行Server的I/O,也就不會觸發auth error、server not response error等,而Ping才有真正的進行。

又學到一招~。