這是職場觀察記,我多次看到了一些很神奇的 Node.js 連接 MySQL 寫法,最後在上線的時候,會在過一陣子後炸掉,甚至在 Serverless 中毀滅。
createConnection 的錯誤
問題其實不在 createConnection 本身,而是機器對 MySQL 連線之後,隔一段時間就會做 Connection Refuse,所以,給定下列 js code,可以看出淺在的風險:
const mysql = require('mysql')
const db = mysql.createConnection({
host: 'localhost',
user: '...',
password: '...',
database: '...',
})
db.connect(function (err) {
if (err) {
throw err
}
console.log('DB connection success')
})
global.db = db
然後對於使用 MVC 程式碼,大致上是這麼使用 剛才的 global db:
// Anonymous xxx function
exports.XXXXX = (req, res) => {
db.query(`SELECT * FROM OOO- WHERE xxx = XXX`, (err, res) => {
if (err) {
console.log(err.message)
return
}
})
}
然後,這個結果就是在上線啟動的數小時後,產生一些錯誤訊息:
events.js:292
throw er; // Unhandled 'error' event
^
Error: read ECONNRESET
at TCP.onStreamRead (internal/stream_base_commons.js:209:20)
Emitted 'error' event on Connection instance at:
...........................................
errno: -104,
code: 'ECONNRESET',
syscall: 'read',
fatal: true
---
此時,建議的解決方案,是把 global.db 換成 dbpool 作法:
:
const mysql = require('mysql')
const dbpool = mysql.createPool({
host: 'localhost',
user: '...',
password: '...',
database: '...',
})
global.dbpool = dbpool
然後,在使用上,可以這麼做:
// Anonymous xxx function
exports.XXXXX = (req, res) => {
dbpool.getConnection((_err1, db) => { // 從池中撈出連線
db.query(`SELECT * FROM OOO- WHERE xxx = XXX`, (err, res) => {
db.release() // 如果沒有要繼續 query,就把連線 release
if (err) {
console.log(err.message)
return
}
})
})
}
需要注意的是 db.release 是在接下來沒有要繼續 query 的時候,要去做的連線重設,假如有多層的 db.query,記得要把 release 放在最後一個 callback 中。
不過在怎樣建議, export.XXXXX 應該要是使用 async 的做法,不過不在本文章討論範圍內。
AWS Serverless 連線問題
當使用第一個 createConnection 這種方法後,在 Deploy 到 AWS 會出現使用啟動 API 的前 6 秒會回應,之後就再也沒回應了,是因為 createConnection 在 connect 會直接卡住 runtime 6 秒,可是問題是 serverless 本身運作機制就不是給你卡 6 秒的,所以自然就會掛掉,那麼啟動 serverless 時,使用 pool 的方式,自然會是還可以的解決方案。
沒有留言:
張貼留言