這是職場觀察記,我多次看到了一些很神奇的 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 的方式,自然會是還可以的解決方案。
沒有留言:
張貼留言