Я хочу, чтобы моя aws lamda ничего не возвращала, пока запрос mysql не будет полностью выполнен на node.js - PullRequest
0 голосов
/ 01 февраля 2020

Сначала я предоставлю код, который представляет собой AWS node.js Лямбда-функцию

    const mysql = require('mysql');
       const con = mysql.createConnection({
        host: 'testtest.ap-southeast-2.rds.amazonaws.com',
        user: 'test',
        password: 'test',
        database: 'test',
    });      
    exports.handler = function(event,context,callback){
        context.callbackWaitsForEmptyEventLoop = false;
        var queryResult=[];
        var searchbyArray = (event.searchby);
        var len = searchbyArray.length;
        getResult(len,searchbyArray,function(err,data){
            if(err){console.log("the error is "+err);}
            else{
                callback(null,data);
            }
        });
};

function getResult(len,searchbyArray,cb){
    var results=[];
    for(var i=0; i<len; i++){
        console.log("before loop"+i);
        var sql ="SELECT * FROM aa_customer_device WHERE id LIKE '%"+searchbyArray[i]+"%'";
        con.query(sql,function(err,result){
        if (err){cb(err,null);}
        else{
            results.push(result);
        }
      });
    }
   cb(null,results);
}

Здесь cb (null, results) выполняется до того, как цикл for завершится после завершения con. query (...) является асин c функцией (угадайте, что она так называется) и всегда возвращает пустой массив в «results», который затем возвращается обработчиком в его функции обратного вызова.

Есть ли В любом случае я могу написать код в node.js, чтобы он соответствовал последовательности, подобной

  • fini sh, выполняя все con.query (...) внутри для l oop
  • pu sh результирующий массив от каждой итерации l oop до массива 'результатов'
  • только после того, как два вышеупомянутых шага были выполнены, вызвать cb (null, results)

здесь происходит то, что cb (null, results) выполняется задолго до того, как для l oop появится возможность сохранить нужную информацию в массиве результатов.

там любой способ выполнить sh то, что я хочу, используя node.js. Мне предложили использовать обещания, asyn c, подождите, но из того, что я прочитал, все эти решения точно не решат мою проблему.

Ответы [ 3 ]

1 голос
/ 01 февраля 2020

Вам необходимо вручную определить, когда последний запрос был выполнен:

function getResult(len,searchbyArray,cb){
    var results=[];
    var requestCount = 0;
    var error = null;

    for(var i=0; i<len; i++){

        requestCount++; // count the requests made

        var sql ="SELECT * FROM aa_customer_device WHERE id LIKE '%"+searchbyArray[i]+"%'";
        con.query(sql,function(err,result){
            // Note: All logic needs to happen here since
            //       this is the ONLY place where code gets
            //       executed in the FUTURE instead of now.

            requestCount --; // count completed requests

            if (err){error = err}
            else{
                results.push(result);

                if (requestCount === 0) {
                    if (error) cb(error,null);   // "return" error
                    else       cb(results);      // "return" results
                }
            }
        });
    }
}

С помощью async / await

Если у вас есть доступ к среде ES6, вы можете использовать async / ждите, чтобы сделать это намного проще для чтения. Для начала вам нужно дать обещание:

// Promisify con.query:
function query (con, sql) {
    return new Promise((resolve, reject) => {
        con.query(sql, (err, result) => {
            if (err) reject(err);
            else     resolve(result);
        });
    });
}

async function getResult(len,searchbyArray,cb){
    var results=[];

    for(var i=0; i<len; i++){
        var sql ="SELECT * FROM aa_customer_device WHERE id LIKE '%"+searchbyArray[i]+"%'";

        try {
            var result = await query(con, sql);
            results.push(result);
        }
        catch (err) {
            cb(err,null);
            return; // stop processing
        }
    }
    cb(results);
}
1 голос
/ 01 февраля 2020

Причина con.query() - функция обратного вызова. Обратные вызовы являются асинхронными, что означает, что они не будут выполняться по порядку. у вас есть два варианта.

  • Использование ключевого слова await (если возможно)
  • Функция обтекания с использованием Promise

На самом деле я не знаю AWS Lambda Mysql support async / await, следовательно, я продемонстрирую второй вариант. Эти два варианта делают одно и то же, но разные шаблоны.

Ситуация здесь - обратные вызовы выполняются асинхронно. Он не будет «ждать» до тех пор, пока не придет результат, поэтому вы получили пустой массив. Вот как ведет себя асин c функция. Очень важно понять c, если вы собираетесь разрабатывать даже серверное приложение в Node js или Java script. Пожалуйста, прокомментируйте, если хотите больше объяснений.

Здесь вы можете обернуть функцию con.query() с помощью Promise.

       const con = mysql.createConnection({
        host: 'testtest.ap-southeast-2.rds.amazonaws.com',
        user: 'test',
        password: 'test',
        database: 'test',
    });      
    exports.handler = async (event,context,callback)=>{
        context.callbackWaitsForEmptyEventLoop = false;
        var queryResult=[];
        var searchbyArray = (event.searchby);
        var len = searchbyArray.length;
        try{
            const result = await Promise.all(getResult(searchbyArray));
        }catch (error){
            console.log("the error is "+err);
        }
};

const getResult = async (searchbyArray) =>{
    const result = searchbyArray.map(searchItem=>{
        var sql =`SELECT * FROM aa_customer_device WHERE id LIKE %${searchItem}%`;
        return new Promise((resolve, reject) => {
            con.query(sql, (err, result) => {
                if (err) 
                    reject(err);
                else     
                    resolve(result);
            });
        });
    })
    return result;
}

Я заменил для l oop на map вместо pu sh для массива и использовал Promise. все это приложение будет работать быстрее, а не ждать в каждом цикле l oop.

1 голос
/ 01 февраля 2020

У вас уже есть проблема. cb(null , results) не ожидает завершения запроса. Чтобы заставить его ждать, как вы уже упоминали, вы можете использовать обещание / asyn c -await.

вот как вы можете написать async/await код для достижения того, что вы пытаетесь сделать.

const mysql = require('mysql');
const promisify = require('util').promisify;

const con = mysql.createConnection({
  host: 'testtest.ap-southeast-2.rds.amazonaws.com',
  user: 'test',
  password: 'test',
  database: 'test',
});

// con.connect uses a callback, we can use util.promify to convert it to promise driven
const connect = promisify(con.connect);

// con.query uses a callback, we can use util.promify to convert it to promise driven
const query = promisify(con.query);

exports.handler = async function (event, context) {
  context.callbackWaitsForEmptyEventLoop = false;
  const queryResult = [];
  const searchbyArray = (event.searchby);
  const len = searchbyArray.length;

  try {

    // wait for the connection to be established.
    await connect();

    const data = getResult(len, searchbyArray);

    // return the lambda success result
    return {
      statusCode: 200,
      responseBody: JSON.stringify(data)
    }

  } catch(err) {
    console.log("the error is " + err)

    // return the lambda failure result
    return {
      statusCode: 500,
      responseBody: err.message
    }
  }
};

async function getResult(len, searchbyArray, cb) {
  const results = [];
  for (const i = 0; i < len; i++) {
    console.log("before loop" + i);

    const sql = `SELECT * FROM aa_customer_device WHERE id LIKE '%${searchbyArray[i]}%'`;

    // wait for the query to complete
    const results = await query(sql);
    results.push(result);
  }
  return results;
}

надеюсь, это поможет, не стесняйтесь спрашивать меня, если вы не понимаете этот код.

...