Knex: Bagaimana cara menggunakan Knex dengan AWS Lambda?

Dibuat pada 20 Jan 2017  ·  34Komentar  ·  Sumber: knex/knex

Saya mengalami masalah dengan penggabungan koneksi saat menguji beberapa kode. Saya mengharapkan fungsi lambda saya dipanggil mungkin beberapa ribu kali selama beberapa detik, dan mengalami masalah dalam mencari cara terbaik untuk terhubung ke db saya. Berikut adalah sangat mirip masalah untuk node / postgres: dasarnya masalahnya adalah bahwa saya harus bisa mendapatkan koneksi dari kolam jika tersedia, namun saya tidak dapat bergantung pada kolam renang yang ada karena bagaimana AWS (unreliably) digunakan ulang wadah lambda.

Pada dasarnya apa yang saya cari adalah cara yang andal untuk mendapatkan atau membuat koneksi ke db saya. Saya belum dapat menemukan contoh apa pun (seperti while(!availableConnections) { tryToGetConnection() } . Apakah saya perlu berinteraksi dengan node-pool ? Bagaimana cara melakukannya dengan Knex?

insightful question

Komentar yang paling membantu

Maaf saya lakukan di tengah kalimat, anak saya baru saja membuang 3 liter air ke lantai: 1st_place_medal: Sebentar lagi saya update komentar di atas ...

Semua 34 komentar

Knex pooling hanya berfungsi jika koneksi dibuat dari proses node yang sama.

Jika instans lambda AWS tidak menjalankan proses node bersama, Anda hanya perlu membuat kumpulan baru dengan koneksi min / maks 1 di setiap instans lambda dan berharap database Anda memiliki pengaturan yang cukup baik untuk memungkinkan ratusan koneksi simultan (dalam RDS, itu tergantung pada ukuran instans ).

Setelah membaca https://forums.aws.amazon.com/thread.jspa?threadID=216000 ini

Sepertinya lambda benar-benar berbagi beberapa proses, jadi jika Anda dapat mengetahui jumlah maksimum kontainer lambda yang dibuat, Anda harus dapat menghitung ukuran kumpulan optimal (setiap kontainer memiliki kumpulan terpisah sehingga total koneksi ke DB adalah kumpulan. maks * jumlah kontainer maks).

Bagaimanapun tidak perlu melakukan koneksi manual yang meminta dari pool, knex menunggu koneksi secara otomatis dan jika semuanya selesai dalam beberapa detik, tidak ada timeout yang tidak akan terpicu pada saat itu.

Jika Anda mendapatkan kesalahan dari DB yang mengatakan bahwa jumlah koneksi maksimum telah tercapai, maka Anda perlu memperkecil ukuran kumpulan maksimum.

Maaf saya lakukan di tengah kalimat, anak saya baru saja membuang 3 liter air ke lantai: 1st_place_medal: Sebentar lagi saya update komentar di atas ...

Terima kasih balasannya. Sepertinya memperkirakan ukuran kolam maksimum akan menjadi taruhan terbaik saya, meskipun jumlah koneksi akan bervariasi secara drastis dari waktu ke waktu.

Agar jelas, tidak ada cara untuk menutup koneksi di Knex, bukan? Hanya kemampuan untuk menghancurkan kumpulan koneksi? Fakta bahwa Lambda kadang-kadang akan menggunakan kembali wadah semacam membuang semuanya.

Menghancurkan kumpulan koneksi juga menghancurkan semua koneksi (menunggu dengan anggun bahwa mereka selesai terlebih dahulu) dan saya kira ketika lambda menghancurkan wadah, semua soket TCP yang terbuka akan menutup secara implisit ketika proses mati.

Saya tidak mengerti mengapa seseorang harus mencoba menutup koneksi secara eksplisit setelah setiap permintaan karena itu akan menghancurkan manfaat penggabungan. Anda akan mendapatkan efek yang sama dengan membuat pool berukuran 1 dan menghancurkannya setelahnya.

Anda juga dapat mengkonfigurasi waktu tunggu idle untuk pool yang secara otomatis akan menutup koneksi jika tidak digunakan dan hanya menunggu tindakan di pool.

Dapatkah saya menggunakan Knex untuk mengirim kueri COPY ke cluster RedShift, dan tidak menunggu hasilnya?

Melakukan ini dengan pg Pool menghentikan kueri segera setelah akhir fungsi Lambda tercapai.

@BardiaAfshin Jika wadah lambda dihancurkan dan semua

Saya juga tidak yakin bagaimana postgresql bereaksi terhadap koneksi sisi klien yang berakhir jika permintaan COPY akan dibatalkan karena transaksi implisit yang belum selesai sebelum membaca nilai hasil ...

Bagaimanapun jika query dapat dikirim atau tidak, cara itu tidak sampai knex, tetapi itu tergantung pada bagaimana aws lambda dan postgresql bekerja.

Pengamatan saya adalah bahwa kueri dimatikan di RedShift dan digulung kembali.

Bagaimanapun tidak perlu melakukan koneksi manual yang meminta dari pool, knex menunggu koneksi secara otomatis dan jika semuanya selesai dalam beberapa detik, tidak ada timeout yang tidak akan terpicu pada saat itu.

Saya menjalankan skrip pengujian beban db dan ini tampaknya tidak benar. Apa pun yang lebih tinggi dari seperti 30 koneksi simultan akan segera habis waktunya, daripada menunggu koneksi terbuka.

Apakah ada cara untuk melepaskan koneksi yang saat ini digunakan secara manual setelah kueri selesai?

Apakah ada yang memiliki kode contoh yang dapat mereka bagikan untuk kita yang baru saja masuk ke AWS Lambda? Saya berharap seseorang dapat berbagi pola dan / atau anti-pola knex / postgres / lambda.

Inilah yang saya gunakan sekarang - saya yakin ini bisa diperbaiki, tetapi berharap sedikit pembenaran, apakah saya berada di jalan yang benar atau tidak ...

'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();
  })
}

Saya berada di perahu yang sama - masih belum menemukan cara terbaik meskipun banyak googling dan pengujian. Yang saya lakukan sekarang adalah:

const dbConfig = require('./db');
const knex = require('knex')(dbConfig);

exports.handler = function (event, context, callback) {
...
connection = {..., pool: { min: 1, max: 1 },

Dengan cara ini sambungan (maks 1 per container) akan tetap hidup sehingga container dapat digunakan kembali dengan mudah. Saya tidak menghancurkan koneksi saya pada akhirnya.

http://blog.rowanudell.com/database-connections-in-lambda/

Tidak yakin apakah ini cara terbaik tetapi sejauh ini berhasil untuk saya.

/mengangkat bahu

@tokopedia

Saya tidak begitu yakin apa yang terjadi jika const knex dideklarasikan - apakah ini tempat koneksi awal diatur? Bisakah seseorang menjelaskan? (Saya berasumsi Anda memiliki info koneksi di dbConfig Anda)

Dalam kode Anda, bukankah koneksi itu sendiri ditimpa dan dibuat ulang setiap kali penangan dipanggil?

Hanya menimpali seseorang yang berada di perahu yang sama, saya tidak beruntung mencoba mencari tahu wadah vs ukuran kolam (sesuai saran @elhigu ). Solusi saya adalah menghancurkan kolam setelah setiap koneksi (saya tahu itu tidak optimal 😒):

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: Cukup setel context.callbackWaitsForEmptyEventLoop = false sebelum menelepon callback.

AWS Lambda menunggu loop acara kosong (secara default). sehingga fungsi bisa memunculkan kesalahan Timeout bahkan callback dijalankan.

Silakan lihat tautan di bawah untuk detailnya:
https://github.com/apex/apex/commit/1fe6e91a46e76c2d5c77877be9ce0c206e9ef9fb

Kepada @elhigu @tgriesser : Ini bukan masalah knex. Ini pasti masalah lingkungan Lambda. Saya pikir tandai masalah ini dengan pertanyaan dan sebaiknya ditutup :)

@mooyoul ya, jelas bukan masalah knex, tapi mungkin masalah dokumentasi ... meskipun saya pikir saya tidak ingin ada hal-hal khusus lambda aws ke dokumen knex, jadi tutup.

Silakan lihat tautan ini
https://stackoverflow.com/questions/49347210/why-aws-lambda-keeps-timing-out-when-using-knex-js
Anda perlu menutup koneksi db jika tidak, Lambda akan berjalan hingga waktu habis.

Adakah yang menemukan pola yang berfungsi sempurna untuk menggunakan Knex dengan Lambda?

Apakah Anda mengalami masalah lain saat menutup koneksi dengan benar?

Hal yang saya coba hindari adalah menutup koneksi dan membuatnya tersedia di semua panggilan Lambda.

Apakah Anda yakin Lambda mengizinkan mempertahankan status antar panggilan?

Lihat bagian node.js dari https://scalegrid.io/blog/how-to-use-mongodb-connection-pooling-on-aws-lambda/ ini menyarankan solusi untuk menutup loop acara yang tidak kosong.

Saya tidak suka membenturkan utas seperti ini, tetapi karena saya pikir itu tersesat di komentar, jawaban @mooyoul di atas bekerja dengan baik untuk kami.

Jika Anda tidak mengubah flag itu menjadi false, Lambda menunggu event loop menjadi kosong. Jika Anda melakukannya, maka fungsi tersebut menyelesaikan eksekusi segera setelah Anda memanggil callback.

Bagi saya, ini berfungsi di mesin lokal saya tetapi tidak setelah diterapkan. Saya agak disesatkan.

Ternyata sumber masuk RDS tidak terbuka untuk fungsi Lambda saya. Solusi yang ditemukan di Stack Overflow : mengubah sumber masuk RDS menjadi 0.0.0.0/0 atau menggunakan VPC.

Setelah memperbarui sumber masuk RDS, saya dapat berhasil menggunakan Lambda dengan Knex.

Runtime Lambda yang saya gunakan adalah Node.js 8.10 dengan paket:

knex: 0.17.0
pg: 7.11.0

Kode di bawah ini menggunakan async juga berfungsi

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
      };
    });
};

Semoga bisa membantu orang-orang yang mungkin menghadapi masalah yang sama di masa depan.

Sesuatu yang saya ingin menarik perhatian orang adalah paket tanpa server-mysql , yang membungkus driver standar mysql tetapi menangani banyak masalah khusus lambda di sekitar manajemen kumpulan koneksi yang dijelaskan di utas ini.

Namun saya tidak berpikir Knex akan bekerja dengan serverless-mysql saat ini (menurut masalah ini ) karena tidak ada cara untuk menukar driver yang berbeda. Mungkin juga ada ketidakcocokan karena serverless-mysql menggunakan promise daripada callback.

Pendekatan terbaik mungkin adalah menambahkan implementasi klien baru di Knex. Saya akan dengan senang hati mencobanya, tetapi akan senang seseorang yang lebih akrab dengan Knex memberi tahu saya jika menurut mereka itu masuk akal / dapat dilakukan?

Juga, saya sedang berpikir untuk sementara, saya bisa menggunakan Knex untuk _build_ tetapi _tidak mengeksekusi_ kueri MySQL. Jadi panggil saja toSQL() dan teruskan hasilnya ke serverless-mysql untuk dieksekusi.

Yang saya ingin tahu adalah apakah Knex dapat dikonfigurasi tanpa koneksi db? Tidak ada gunanya membuka koneksi yang tidak pernah digunakan.

Akankah pekerjaan berikut ini berhasil?

connection = {..., pool: { min: 0, max: 0 ) },

@disbelief Anda dapat menginisialisasi knex tanpa koneksi. Ada contoh bagaimana melakukannya di akhir bagian ini di dokumen https://knexjs.org/#Installation -client

const knex = require('knex')({client: 'mysql'});

const generatedQuery = knex('table').where('id',1).toSQL().toNative();

@elhigu ah keren, makasih. Akan mencobanya untuk sementara.

Pembaruan: hal di atas tampaknya tidak berfungsi. Knex melontarkan kesalahan jika tidak dapat membuat koneksi db, bahkan jika tidak pernah ada panggilan untuk mengeksekusi kueri.

@Tidak percaya apakah Anda menemukan solusi untuk itu?

@nurhadi Saat ini saya hanya membuat kueri dengan squel , memanggil toString() padanya, dan meneruskannya ke klien serverless-mysql .

@ Ketidakpercayaan Ini mengejutkan saya bahwa membangun kueri gagal tanpa koneksi db.

Apakah Anda keberatan memposting kode & konfigurasi yang Anda gunakan untuk membuat klien knex? Juga versi knex.

Berikut ini bekerja dengan baik untuk saya
Node 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 ] }

Sesuai cara kerja daur ulang sumber daya Lambda, instance Knex harus selalu disimpan di luar fungsi atau kelas apa pun. Selain itu, penting untuk memiliki maks 1 koneksi di kumpulan.

Sesuatu seperti:

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;
  }
}

Dengan cara ini, Anda akan mendapatkan hasil maksimal dari daur ulang Lambda, yaitu setiap wadah yang diaktifkan (dibekukan) hanya akan memiliki koneksi yang sama.

Sebagai catatan tambahan, perlu diingat bahwa Lambda menskalakan secara default jika Anda tidak membatasi jumlah container serentak.

Saya sudah menjalankan Knex di Lambda selama hampir satu tahun sekarang tanpa masalah. Saya mendeklarasikan instance Knex saya di luar fungsi Lambda saya dan menggunakan context.callbackWaitsForEmptyEventLoop = false seperti yang disebutkan di posting lain.

Yang mengatakan, selama beberapa hari terakhir, sesuatu tampaknya telah berubah di sisi Lambda karena saya sekarang melihat lonjakan koneksi yang besar di Postgres; koneksi sepertinya tidak ditutup.

Apakah orang lain yang menggunakan pendekatan yang disebutkan di atas melihat peluang selama beberapa hari terakhir ini?

@jamesdixon baru saja membaca ini sekarang sambil memfaktorkan ulang beberapa implementasi knex kami di lambda. Ada pembaruan tentang ini? Apakah context.callbackWaitsForEmptyEventLoop = false berhenti bekerja?

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

npow picture npow  ·  3Komentar

marianomerlo picture marianomerlo  ·  3Komentar

zettam picture zettam  ·  3Komentar

mishitpatel picture mishitpatel  ·  3Komentar

mattgrande picture mattgrande  ·  3Komentar