ããã€ãã®ã³ãŒãããã¹ãããŠãããšãã«ãæ¥ç¶ããŒã«ã§åé¡ãçºçããŠããŸãã ã©ã ãé¢æ°ãæ°ç§éã«æ°åååŒã³åºãããããšãæåŸ ããŠãããããŒã¿ããŒã¹ã«æ¥ç¶ããããã®æè¯ã®æ¹æ³ãèŠã€ããã®ã«èŠåŽããŠããŸãã ããã§ã¯éåžžã«äŒŒãŠããŸãåé¡ããŒã/ postgresã®ããã«ïŒåºæ¬çã«åé¡ã¯1ã€ãå©çšå¯èœãªå Žåãç§ã¯ããããç§ã¯ã®ã§ãã©ã®ããã«AWSïŒåœãŠã«ãªããã«ïŒåå©çšãæ¢åã®ããŒã«ã«äŸåããããšã¯ã§ããŸãããããŒã«ããæ¥ç¶ãååŸã§ããããã«ããå¿ èŠããããšããããšã§ãã©ã ãã³ã³ããã
åºæ¬çã«ç§ãæ¢ããŠããã®ã¯ãããŒã¿ããŒã¹ãžã®æ¥ç¶ã確å®ã«ååŸãŸãã¯äœæããæ¹æ³ã§ãã äŸãèŠã€ããããšãã§ããŸããã§ããïŒ while(!availableConnections) { tryToGetConnection() }
ã node-pool
ãšå¯Ÿè©±ããå¿
èŠããããŸããïŒKnexã§ãããè¡ãã«ã¯ã©ãããã°ããã§ããïŒ
KnexããŒãªã³ã°ã¯ãæ¥ç¶ãåãããŒãããã»ã¹ããè¡ãããå Žåã«ã®ã¿æ©èœããŸãã
AWSã©ã ãã€ã³ã¹ã¿ã³ã¹ãå ±æããŒãããã»ã¹ãå®è¡ããŠããªãå Žåã¯ãåã©ã ãã€ã³ã¹ã¿ã³ã¹ã«æå°/æ倧æ¥ç¶1ã®æ°ããããŒã«ãäœæããå¿ èŠããããããŒã¿ããŒã¹ã«æ°çŸã®åææ¥ç¶ãèš±å¯ããã®ã«ååãªèšå®ãããããšãæåŸ ããŸãïŒRDSã§ã¯ã€ã³ã¹ã¿ã³ã¹ãµã€ãºã«ãã£ãŠç°ãªããŸãïŒ ïŒã
ãããèªãã åŸhttps://forums.aws.amazon.com/thread.jspa?threadID=216000
ã©ã ãã¯å®éã«ããã€ãã®ããã»ã¹ãå ±æããŠããããã«èŠããã®ã§ãäœæãããã©ã ãã³ã³ãããŒã®æ倧æ°ãææ¡ã§ããã°ãæé©ãªããŒã«ãµã€ãºãèšç®ã§ããã¯ãã§ãïŒåã³ã³ãããŒã«ã¯åå¥ã®ããŒã«ããããããDBãžã®æ¥ç¶ã®åèšã¯ããŒã«ã«ãªããŸãã max *æ倧ã³ã³ããæ°ïŒã
ãšã«ãããããŒã«ããæåã§æ¥ç¶ãèŠæ±ããå¿ èŠã¯ãããŸãããknexã¯èªåçã«æ¥ç¶ãåŸ æ©ããæ°ç§ã§ãã¹ãŠãçµäºããå Žåããã®æéå ã«ã¿ã€ã ã¢ãŠããããªã¬ãŒãããããšã¯ãããŸããã
æ倧æ¥ç¶æ°ã«éããããšã瀺ããšã©ãŒãDBããçºçããå Žåã¯ãæ倧ããŒã«ãµã€ãºãå°ããããå¿ èŠããããŸãã
ç³ãèš³ãããŸããããæã®éäžã§ã³ãããããŸãããç§ã®åäŸã¯3ãªããã«ã®æ°Žãåºã«æããŸããïŒ1st_place_medalïŒäžèšã®ã³ã¡ã³ããããã«æŽæ°ããŸã...
è¿ä¿¡ããã ãããããšãããããŸãã æ¥ç¶æ°ã¯æéã®çµéãšãšãã«å€§å¹ ã«å€åããŸãããæ倧ããŒã«ãµã€ãºãèŠç©ããããšãæåã®çã®ããã§ãã
æ確ã«ããããã«ãKnexã§æ¥ç¶ãéããæ¹æ³ã¯ãããŸããããïŒ æ¥ç¶ããŒã«ãç Žæ£ããæ©èœã®ã¿ã§ããïŒ Lambdaãã³ã³ãããåå©çšããããšããããšããäºå®ã¯ããã¹ãŠãæšãŠãŠããŸããŸãã
æ¥ç¶ããŒã«ãç Žæ£ãããšããã¹ãŠã®æ¥ç¶ãç Žæ£ããïŒæåã«å®äºããã®ãåªé ã«åŸ æ©ããŸãïŒãã©ã ããã³ã³ãããŒãç Žæ£ãããšãããã»ã¹ãçµäºãããšãéããŠãããã¹ãŠã®TCPãœã±ãããæé»çã«éãããããšæããŸãã
ããŒãªã³ã°ã®å©ç¹ã倱ããããããåãªã¯ãšã¹ãã®åŸã«æ瀺çã«æ¥ç¶ãéããããšããå¿ èŠãããçç±ãããããŸããã ãµã€ãº1ã®ããŒã«ãäœæããåŸã§ç Žæ£ããŠãåãå¹æãåŸãããŸãã
ããŒã«ã®ã¢ã€ãã«ã¿ã€ã ã¢ãŠããæ§æããããšãã§ããŸããããã¯ã䜿çšãããŠããããããŒã«ã§ã®ã¢ã¯ã·ã§ã³ãåŸ æ©ããŠããå Žåã«æ¥ç¶ãèªåçã«éããŸãã
Knexã䜿çšããŠCOPYã¯ãšãªãRedShiftã¯ã©ã¹ã¿ãŒã«éä¿¡ããçµæãåŸ ããªãããšã¯ã§ããŸããïŒ
pg Poolã§ãããè¡ããšãLambdaé¢æ°ã®çµããã«éãããšããã«ã¯ãšãªãçµäºããŸãã
@BardiaAfshinã©ã ãé¢æ°ã®çµäºã«éãããšãã«ã©ã ãã³ã³ãããç Žæ£ããããã®ãã¹ãŠã®ãœã±ããã解æŸãããå Žåãdbã¯ãšãªãçµäºããçµäºããªãå¯èœæ§ããããŸãã
çµæå€ãèªã¿åãåã«æé»ã®ãã©ã³ã¶ã¯ã·ã§ã³ãçµäºããŠããªãããã«COPYã¯ãšãªãããŒã«ããã¯ãããå Žåãpostgresqlãã¯ã©ã€ã¢ã³ãåŽã®æ¥ç¶ã®çµäºã«ã©ã®ããã«åå¿ãããã¯ããããŸãã...
ãšã«ãããã¯ãšãªãéä¿¡ã§ãããã©ããã¯knex次第ã§ã¯ãããŸããããawslambdaãšpostgresqlãã©ã®ããã«æ©èœãããã«ãã£ãŠç°ãªããŸãã
ç§ã®èŠ³å¯ã§ã¯ãã¯ãšãªã¯RedShiftã§åŒ·å¶çµäºãããããŒã«ããã¯ãããŸãã
ãšã«ãããããŒã«ããæåã§æ¥ç¶ãèŠæ±ããå¿ èŠã¯ãããŸãããknexã¯èªåçã«æ¥ç¶ãåŸ æ©ããæ°ç§ã§ãã¹ãŠãçµäºããå Žåããã®æéå ã«ã¿ã€ã ã¢ãŠããããªã¬ãŒãããããšã¯ãããŸããã
ããŒã¿ããŒã¹è² è·ãã¹ãã¹ã¯ãªãããå®è¡ããŠããŸãããããã¯æ£ãããªãããã§ãã 30ã®åææ¥ç¶ã®ãããªãã®ããé«ããã®ã¯ãéããŠããæ¥ç¶ãåŸ ã€ã®ã§ã¯ãªããããã«ã¿ã€ã ã¢ãŠãããŸãã
ã¯ãšãªãå®è¡ãããããçŸåšäœ¿çšãããŠããæ¥ç¶ãæåã§è§£æŸããæ¹æ³ã¯ãããŸããïŒ
AWS Lambdaãå§ããã°ããã®ç§ãã¡ã®ããã«å ±æã§ãããµã³ãã«ã³ãŒãã誰ããæã£ãŠããŸããïŒ èª°ããknex / postgres / lambdaã®ãã¿ãŒã³ãã¢ã³ããã¿ãŒã³ãå ±æã§ããããšãé¡ã£ãŠããŸãã
ãããç§ãä»äœ¿ã£ãŠãããã®ã§ã-ããã¯æ¹åã§ãããšç¢ºä¿¡ããŠããŸãããç§ãæ£ããéãé²ãã§ãããã©ããã«ã€ããŠå°ãã®èšŒæ ãæåŸ ããŠããŸã...
'use strict';
var pg = require('pg');
function initKnex(){
return require('knex')({
client: 'pg',
connection: { ...details... }
});
}
module.exports.hello = (event, context) =>
{
var knex = initKnex();
// Should I be returning knex here or in the final catch?
knex
.select('*')
.from('my_table')
.then(function (rows) {
context.succeed('Succeeded: ' + JSON.stringify(rows || []));
})
.catch(function (error) {
context.fail(error);
})
.then(function(){
// is destroy overkill? - is there an option for knex.client.release, etc?
knex.destroy();
})
}
ç§ã¯åãè¹ã«ä¹ã£ãŠããŸã-ããããã®ã°ãŒã°ã«ãšãã¹ãã«ããããããããŸã æåã®æ¹æ³ãäœã§ããããç解ããŠããŸããã ç§ãä»ããŠããããšã¯ïŒ
const dbConfig = require('./db');
const knex = require('knex')(dbConfig);
exports.handler = function (event, context, callback) {
...
connection = {..., pool: { min: 1, max: 1 },
ãã®ããã«ããŠãæ¥ç¶ïŒã³ã³ãããŒããšã«æ倧1ã€ïŒãç¶æããããããã³ã³ãããŒãç°¡åã«åå©çšã§ããŸãã ç§ã¯æåŸã«ç§ã®æ¥ç¶ãç Žå£ããŸããã
http://blog.rowanudell.com/database-connections-in-lambda/
ãããæåã®æ¹æ³ãã©ããã¯ããããŸãããããããŸã§ã®ãšããããŸããããŸããã
/è©ããããã
@austingayler
const knex
ã宣èšããããšãã«äœãèµ·ãããæ£ç¢ºã«ã¯ããããŸãã-ããã¯åææ¥ç¶ãã»ããã¢ãããããå Žæã§ããïŒ èª°ããæ確ã«ããããšãã§ããŸããïŒ ïŒdbConfigã«æ¥ç¶æ
å ±ããããšæ³å®ããŠããŸãïŒ
ããªãã®ã³ãŒãã§ã¯ããã³ãã©ãŒãåŒã³åºããããã³ã«æ¥ç¶èªäœãäžæžããããŠåäœæãããŠããŸãããïŒ
åãããŒãã«ä¹ã£ãŠãã人ã«ãã£ã€ã ã鳎ãããŠããã ãã§ãã³ã³ãããšããŒã«ã®ãµã€ãºãæ¯èŒããã®ã«ããŸãéããããŸããã§ããïŒ
const knex = require('knex');
const client = knex(dbConfig);
client(tableName).select('*')
.then((result) => {
return Promise.all([
result,
client.destroy(),
])
})
.then(([ result ]) => {
return result;
});
TL; DRïŒã³ãŒã«ããã¯ãåŒã³åºãåã«
context.callbackWaitsForEmptyEventLoop = false
èšå®ããã ãã§ãã
AWS Lambdaã¯ã空ã®ã€ãã³ãã«ãŒããåŸ æ©ããŸãïŒããã©ã«ãïŒã ãã®ãããã³ãŒã«ããã¯ãå®è¡ãããŠããé¢æ°ã¯ã¿ã€ã ã¢ãŠããšã©ãŒãã¹ããŒããå¯èœæ§ããããŸãã
詳现ã«ã€ããŠã¯ã以äžã®ãªã³ã¯ãåç
§ããŠãã ããã
https://github.com/apex/apex/commit/1fe6e91a46e76c2d5c77877be9ce0c206e9ef9fb
@elhigu @tgriesserãžïŒããã¯knexã®åé¡ã§ã¯ãããŸããã ããã¯ééããªãã©ã ãç°å¢ã®åé¡ã§ãã ç§ã¯ãã®åé¡ã«è³ªåã®ã¿ã°ãä»ããŠãéããã®ãè¯ããšæããŸã:)
@mooyoulãããééããªãknexã®åé¡ã§ã¯ãªãããããã¥ã¡ã³ãã®åé¡ãããããªã... knexdocsã«awslambdaåºæã®ãã®ã¯å¿ èŠãªããšæãã®ã§ãéããŸãã
ãã®ãªã³ã¯ãèŠãŠãã ãã
https://stackoverflow.com/questions/49347210/why-aws-lambda-keeps-timing-out-when-using-knex-js
dbæ¥ç¶ãéããå¿
èŠããããŸããããããªããšãLambdaãã¿ã€ã ã¢ãŠããããŸã§å®è¡ãããŸãã
KnexãLambdaã§äœ¿çšããããã«å®ç§ã«æ©èœãããã¿ãŒã³ãèŠã€ãã人ã¯ããŸããïŒ
æ¥ç¶ãæ£ããéãããšãã«ä»ã«åé¡ããããŸããïŒ
ç§ãé¿ããããšããŠããã®ã¯ãæ¥ç¶ãéããŠãã©ã ãã®åŒã³åºãå šäœã§å©çšã§ããããã«ããããšã§ãã
LambdaãåŒã³åºãéã®ç¶æ ã®ç¶æãèš±å¯ããŸããïŒ
https://scalegrid.io/blog/how-to-use-mongodb-connection-pooling-on-aws-lambda/ã®node.jsã®éšåã確èªããŠ
ç§ã¯ãã®ããã«ã¹ã¬ãããã¶ã€ããã®ã¯å¥œãã§ã¯ãããŸããããã³ã¡ã³ãã§å€±ãããŠãããšæãã®ã§ãäžèšã®@mooyoulã®çãã¯ç§ãã¡ã«ãšã£ãŠããŸããããŸããã
ãã®ãã©ã°ãfalseã«ããªããšãLambdaã¯ã€ãã³ãã«ãŒãã空ã«ãªãã®ãåŸ ã¡ãŸãã ããããå Žåãã³ãŒã«ããã¯ãåŒã³åºããšããã«é¢æ°ã¯å®è¡ãçµäºããŸãã
ç§ã«ãšã£ãŠã¯ãããŒã«ã«ãã·ã³ã§ã¯æ©èœããŸãããããããã€åŸã¯æ©èœããŸããã§ããã ç§ã¯ã¡ãã£ãšèª€è§£ãæããŸããã
RDSã€ã³ããŠã³ããœãŒã¹ãç§ã®Lambdaé¢æ°ã«å¯ŸããŠéãããŠããªãããšãããããŸããã Stack Overflowã§è§£æ±ºçãèŠã€ãããŸããïŒRDSã€ã³ããŠã³ããœãŒã¹ã0.0.0.0/0
ããVPCã䜿çšããŸãã
RDSã€ã³ããŠã³ããœãŒã¹ãæŽæ°ããåŸãKnexã§Lambdaãæ£åžžã«å®è¡ã§ããŸãã
ç§ã䜿çšããŠããLambdaã©ã³ã¿ã€ã ã¯Node.js 8.10
ãããã±ãŒãžã¯æ¬¡ã®ãšããã§ãã
knex: 0.17.0
pg: 7.11.0
éåæã䜿çšãã以äžã®ã³ãŒããæ©èœããŸã
const Knex = require('knex');
const pg = Knex({ ... });
module.exports. submitForm = async (event) => {
const {
fields,
} = event['body-json'] || {};
return pg('surveys')
.insert(fields)
.then(() => {
return {
status: 200
};
})
.catch(err => {
return {
status: 500
};
});
};
ããŸãããã°ãããã¯å°æ¥åãåé¡ã«ééãããããããªã人ã ãå©ããã§ãããã
ç§ã人ã
ã®æ³šæãåŒãããã®ã¯ã serverless-mysqlããã±ãŒãžã§ããããã¯ãæšæºã®mysql
ãã©ã€ããŒãã©ããããŸããããã®ã¹ã¬ããã§èª¬æãããŠããæ¥ç¶ããŒã«ç®¡çã«é¢ããã©ã ãåºæã®åé¡ç¹ã®å€ããåŠçããŸãã
ãã ããå¥ã®ãã©ã€ããŒã«äº€æããæ¹æ³ããªããããçŸæç¹ã§ã¯ïŒãã®åé¡ã«ãããšïŒKnexãserverless-mysql
ã§åäœãããšã¯æããŸããã serverless-mysql
ã¯ã³ãŒã«ããã¯ã®ä»£ããã«promiseã䜿çšãããããéäºææ§ãååšããå¯èœæ§ããããŸãã
æåã®ã¢ãããŒãã¯ãããããKnexã«æ°ããã¯ã©ã€ã¢ã³ãå®è£ ãè¿œå ããããšã§ãã ç§ã¯ãããè©ŠããŠã¿ãŠããããã§ãããKnexã«ç²ŸéããŠãã誰ãã«ããããåçç/å®è¡å¯èœã ãšæããã©ããæããŠãããããã§ããïŒ
ãŸãããã®éãKnexã䜿çšããŠMySQLã¯ãšãªã_ãã«ã_ããããšã¯ã§ããŸãããå®è¡ããããšã¯ã§ããŸããã§ããã ãããã£ãŠã toSQL()
ãåŒã³åºããåºåãserverless-mysql
ã«æž¡ããŠå®è¡ããŸãã
ç§ãçåã«æã£ãŠããã®ã¯ãããŒã¿ããŒã¹æ¥ç¶ãªãã§Knexãæ§æã§ãããã©ããã§ãã 䜿çšãããããšã®ãªãæ¥ç¶ãéãæå³ã¯ãããŸããã
次ã¯æ©èœããŸããïŒ
connection = {..., pool: { min: 0, max: 0 ) },
@disbeliefæ¥ç¶ããã«knexãåæåã§ããŸãã ãã®ã»ã¯ã·ã§ã³ã®æåŸã«ãããã¥ã¡ã³ãhttps://knexjs.org/#Installation-clientã«ãããè¡ãæ¹æ³ã®äŸããã
const knex = require('knex')({client: 'mysql'});
const generatedQuery = knex('table').where('id',1).toSQL().toNative();
@elhiguãããã£ããããããããšãã æ«å®çã«ãã®ã·ã§ãããäžããŸãã
æŽæ°ïŒäžèšã¯æ©èœããŠããªãããã§ãã Knexã¯ãã¯ãšãªãå®è¡ããããã®åŒã³åºãããŸã£ãããªãå Žåã§ããdbæ¥ç¶ã確ç«ã§ããªãå Žåã«ãšã©ãŒãã¹ããŒããŸãã
@disbeliefããªãã¯ãã®è§£æ±ºçãèŠã€ããŸãããïŒ
@fdecampredonãããã çŸæç¹ã§ã¯ã squelã䜿çšããŠã¯ãšãªãtoString()
ãåŒã³åºããŠã serverless-mysql
ã¯ã©ã€ã¢ã³ãã«æž¡ããŠããã ãã§ãã
@disbeliefããŒã¿ããŒã¹æ¥ç¶ãªãã§ã¯ãšãªã®æ§ç¯ã倱æããã®ã¯ç§ã«ãšã£ãŠé©ãã§ãã
knexã¯ã©ã€ã¢ã³ãã®æ§ç¯ã«äœ¿çšããŠããã³ãŒããšæ§æãæçš¿ããŠããã ããŸãããïŒ ãŸããknexããŒãžã§ã³ã
以äžã¯ç§ã«ãšã£ãŠã¯ããŸããããŸã
ããŒãv8.11.1
mysql
ïŒ2.13.0
knex
ïŒ0.18.3
const k = require('knex')
const client = k({ client: 'mysql' })
console.log('Knex version:', require('knex/package.json').version)
// => 0.18.3
console.log('sql:', client('table').where('id',1).toSQL().toNative())
// => { sql: 'select * from `table` where `id` = ?', bindings: [ 1 ] }
Lambdaã®ãªãœãŒã¹ãªãµã€ã¯ã«ã®ä»çµã¿ã«åŸã£ãŠã Knex
ã€ã³ã¹ã¿ã³ã¹ã¯åžžã«é¢æ°ãŸãã¯ã¯ã©ã¹ã®å€éšã«ä¿æããå¿
èŠããããŸãã ãŸããããŒã«å
ã®æ¥ç¶ã§æ倧1ãæã£ãŠããããšãéèŠã§ãã
äœãã®ãããªãã®ïŒ
const Knex = require('knex');
let instance = null;
module.exports = class DatabaseManager {
constructor({ host, user, password, database, port = 3306, client = 'mysql', pool = { min: 1, max: 1 }}) {
this._client = client;
this._poolOptions = pool;
this._connectionOptions = {
host: DB_HOST || host,
port: DB_PORT || port,
user: DB_USER || user,
password: DB_PASSWORD || password,
database: DB_NAME || database,
};
}
init() {
if (instance !== null) {
return;
}
instance = Knex({
client: this._client,
pool: this._poolOptions,
connection: this._connectionOptions,
debug: process.env.DEBUG_DB == true,
asyncStackTraces: process.env.DEBUG_DB == true,
});
}
get instance() {
return instance;
}
}
ãã®ããã«ããŠãLambdaã®ãªãµã€ã¯ã«ãæ倧éã«æŽ»çšã§ããŸããã€ãŸããã¢ã¯ãã£ãåãããïŒåçµãããïŒåã³ã³ãããŒã¯åãæ¥ç¶ã®ã¿ãä¿æããŸãã
è£è¶³ãšããŠãåæã³ã³ãããŒã®æ°ãå¶éããªãå ŽåãLambdaã¯ããã©ã«ãã§ã¹ã±ãŒã«ã¢ãŠãããããšã«æ³šæããŠãã ããã
Knexãã©ã ãã§1幎è¿ãå®è¡ããŠããŠãåé¡ã¯ãããŸããã ä»ã®æçš¿ã§èšåãããŠããããã«ãLambdaé¢æ°ã®å€éšã§Knexã€ã³ã¹ã¿ã³ã¹ã宣èšãã context.callbackWaitsForEmptyEventLoop = false
ãå©çšããŠããŸãã
ãšã¯èšããã®ã®ããã®1æ¥ã§ãPostgresã§æ¥ç¶ãå€§å¹ ã«æ¥å¢ããŠããã®ãèŠãŠãLambdaåŽã§äœããå€ãã£ãããã§ãã æ¥ç¶ãéããããŠããªãããã§ãã
åè¿°ã®ã¢ãããŒãã䜿çšããŠããä»ã®èª°ãããéå»1æ¥ã»ã©ã§ãã£ã³ã¹ãèŠãããšããããŸããïŒ
@jamesdixonã¯ãã©ã ãã§ã®knexå®è£
ã®äžéšããªãã¡ã¯ã¿ãªã³ã°ããªããããããèªãã§ããŸãã ããã«é¢ããæŽæ°ã¯ãããŸããïŒ context.callbackWaitsForEmptyEventLoop = false
ãæ©èœããªããªããŸãããïŒ
æãåèã«ãªãã³ã¡ã³ã
ç³ãèš³ãããŸããããæã®éäžã§ã³ãããããŸãããç§ã®åäŸã¯3ãªããã«ã®æ°Žãåºã«æããŸããïŒ1st_place_medalïŒäžèšã®ã³ã¡ã³ããããã«æŽæ°ããŸã...