Last active
January 8, 2018 11:31
-
-
Save shimataro/10c378802f078990581873d640f5f3f4 to your computer and use it in GitHub Desktop.
リソースマネージャーを作ってみた
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class ResourceManager { | |
constructor() { | |
this._resourceFunctionsMap = {}; | |
this._resourceSingletonMap = {}; | |
this._closeCallbacks = []; | |
this._closed = false; | |
} | |
/** | |
* リソース登録 | |
* @param {string} name | |
* @param {function(*)} open | |
* @param {function(*)} close | |
*/ | |
register(name, open, close) { | |
this._resourceFunctionsMap[name] = { | |
open: open, | |
close: close, | |
}; | |
} | |
/** | |
* リソース取得 | |
* @param {string} name | |
* @param {?*} options | |
* @return {*} | |
*/ | |
open(name, options = null) { | |
const resourceFunctionsMap = this._resourceFunctionsMap; | |
if (!resourceFunctionsMap.hasOwnProperty(name)) { | |
// リソース名が登録されていない | |
throw new Error(`ResourceManager: resource name "${name}" is unregistered`); | |
} | |
if (this._closed) { | |
// すでに閉じられていたらエラー | |
// (クライアントからの接続が途中で切れた場合、リソース確保前にcloseメソッドがコールされる場合がある) | |
throw new Error(`ResourceManager: resources are already closed`); | |
} | |
const resourceFunctions = resourceFunctionsMap[name]; | |
const resource = resourceFunctions.open(options); | |
this._closeCallbacks.push(() => { | |
resourceFunctions.close(resource); | |
}); | |
return resource; | |
} | |
/** | |
* リソース取得(Singleton) | |
* @param {string} name | |
* @param {?*} options | |
* @return {*} | |
*/ | |
openSingle(name, options = null) { | |
const key = JSON.stringify([name, options]); | |
const resourceSingletonMap = this._resourceSingletonMap; | |
if (!resourceSingletonMap.hasOwnProperty(key)) { | |
resourceSingletonMap[key] = this.open(name, options); | |
} | |
return resourceSingletonMap[key]; | |
} | |
/** | |
* 取得したリソースをすべて解放 | |
* res.on("finish") など、処理完了のタイミングでコール | |
*/ | |
close() { | |
const callbacks = this._closeCallbacks; | |
while (callbacks.length > 0) { | |
// 登録と逆順にコール | |
const callback = callbacks.pop(); | |
callback(); | |
} | |
this._closed = true; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import express from "express"; | |
// メイン処理 | |
{ | |
const app = express(); | |
app.listen(3000); | |
app | |
.use(middleware) | |
.get("/", (req, res, next) => { | |
// openSingleは同じリソース名・同じオプションで何度コールしても最初のリソースを使いまわす | |
const conn = req.objResourceManager.openSingle("mysql", {/* 接続オプション */}); | |
// いろいろ処理 | |
res.send("OK"); | |
}); | |
} | |
/** | |
* Express.jsのミドルウェア(最初に登録) | |
*/ | |
function middleware(req, res, next) { | |
// リソースマネージャーをreqのプロパティに追加 | |
const objResourceManager = new ResourceManager(); | |
req.objResourceManager = objResourceManager; | |
// リソース名・取得方法・解放方法を指定 | |
objResourceManager.register( | |
"mysql", | |
(options) => { | |
return mysql.createConnection(options); | |
}, | |
(conn) => { | |
conn.end(); | |
}); | |
// 終了時にリソース解放 | |
res | |
.on("close", () => { | |
// 切断 | |
objResourceManager.close(); | |
}) | |
.on("finish", () => { | |
// 処理完了 | |
objResourceManager.close(); | |
}); | |
if (res.socket.destroyed) { | |
// そもそもこの時点で切断されていた | |
objResourceManager.close(); | |
} | |
next(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment