1

I have an aws lambda function that is return null when it hits request. My test for the request worked until I set up the database connection. Any thoughts as to why it's not running request?

The logs show the ready state as 1 then it returns null.

***Edit

That was the first issue, once I promised it I had an issue with the database connection going away before executing my schema methods. I'll answer below.

const request = require('request')
const tickerController = require('./controllers/ticker');

const mongoose = require('mongoose');

let conn = null;

const uri = `mongodb+srv://${process.env.dbUser}:${process.env.dbPassword}@cluster0-oj6p1.mongodb.net/test?retryWrites=true&w=majority`;

exports.handler = async function main(event, context, lambdaCallback) {
  // Make sure to add this so you can re-use `conn` between function calls.
  // See https://www.mongodb.com/blog/post/serverless-development-with-nodejs-aws-lambda-mongodb-atlas
    context.callbackWaitsForEmptyEventLoop = false;

    // Because `conn` is in the global scope, Lambda may retain it between
    // function calls thanks to `callbackWaitsForEmptyEventLoop`.
    // This means your Lambda function doesn't have to go through the
    // potentially expensive process of connecting to MongoDB every time.
    if (conn == null) {
      conn = await mongoose.createConnection(uri, {
        // Buffering means mongoose will queue up operations if it gets
        // disconnected from MongoDB and send them when it reconnects.
        // With serverless, better to fail fast if not connected.
        bufferCommands: false, // Disable mongoose buffering
        bufferMaxEntries: 0, // and MongoDB driver buffering
        useUnifiedTopology: true,
        useNewUrlParser: true
      });
      // conn.model('Test', new mongoose.Schema({ name: String }));
      // console.log(conn);
      console.log(conn.readyState);

      runRequest(lambdaCallback);
  // })
  }
};

function runRequest(lambdaCallback) {
  request('https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=BKUH&apikey=' + process.env.apiKey, (err, response, body) => {
        console.log('Request ran');
        if (err) {
          console.error(err);
          done(502, '{"message", "Error retrieving ticker data"}', 'application/json', lambdaCallback);
        } else {
          try {
            .....
2
  • where is done coming from ? Commented Jan 5, 2020 at 12:10
  • done was a function underneath I wrote. I solved the issue, I'll write it below. Commented Jan 5, 2020 at 18:04

2 Answers 2

1

I would start using the promises/async/await instead of callback pattern. Something like

const request = require("request");
const tickerController = require("./controllers/ticker");

const mongoose = require("mongoose");

let conn = null;

const uri = `mongodb+srv://${process.env.dbUser}:${process.env.dbPassword}@cluster0-oj6p1.mongodb.net/test?retryWrites=true&w=majority`;

exports.handler = async event => {
  // Make sure to add this so you can re-use `conn` between function calls.
  // See https://www.mongodb.com/blog/post/serverless-development-with-nodejs-aws-lambda-mongodb-atlas
  context.callbackWaitsForEmptyEventLoop = false;

  // Because `conn` is in the global scope, Lambda may retain it between
  // function calls thanks to `callbackWaitsForEmptyEventLoop`.
  // This means your Lambda function doesn't have to go through the
  // potentially expensive process of connecting to MongoDB every time.
  if (conn == null) {
    conn = await mongoose.createConnection(uri, {
      // Buffering means mongoose will queue up operations if it gets
      // disconnected from MongoDB and send them when it reconnects.
      // With serverless, better to fail fast if not connected.
      bufferCommands: false, // Disable mongoose buffering
      bufferMaxEntries: 0, // and MongoDB driver buffering
      useUnifiedTopology: true,
      useNewUrlParser: true
    });
    // conn.model('Test', new mongoose.Schema({ name: String }));
    // console.log(conn);
    console.log(conn.readyState);

    const body = await runRequest();
    return body;
    // })
  }
};

function runRequest() {
  return new Promise((resolve, reject) => {
    request(
      "https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=BKUH&apikey=" +
        process.env.apiKey,
      (err, response, body) => {
        console.log("Request ran");
        if (err) {
          console.error(err);
          reject(err);
        }
        resolve(body);
      }
    );
  });
}

Sign up to request clarification or add additional context in comments.

1 Comment

There is an issue with using promises there that will disconnect the database connection before I access the schema
1

So the answer with the database connection issue was to refactor my code to one file, and use the 'conn' variable as a global object to create my model, like so..

let conn = null;
let Ticker = null;

const uri = `mongodb+srv://${process.env.dbUser}:${process.env.dbPassword}@cluster0-oj6p1.mongodb.net/bakhu?retryWrites=true&w=majority`;

exports.handler = async function main(event, context, lambdaCallback) {
  // Make sure to add this so you can re-use `conn` between function calls.
  // See https://www.mongodb.com/blog/post/serverless-development-with-nodejs-aws-lambda-mongodb-atlas
    context.callbackWaitsForEmptyEventLoop = false;

    // Because `conn` is in the global scope, Lambda may retain it between
    // function calls thanks to `callbackWaitsForEmptyEventLoop`.
    // This means your Lambda function doesn't have to go through the
    // potentially expensive process of connecting to MongoDB every time.
    if (conn == null) {
      conn = await mongoose.createConnection(uri, {
        // Buffering means mongoose will queue up operations if it gets
        // disconnected from MongoDB and send them when it reconnects.
        // With serverless, better to fail fast if not connected.
        bufferCommands: false, // Disable mongoose buffering
        bufferMaxEntries: 0, // and MongoDB driver buffering
        useUnifiedTopology: true,
        useNewUrlParser: true
      });
      // conn.model('Test', new mongoose.Schema({ name: String }));
      // console.log(conn);
      console.log(conn.readyState);

      const Schema = mongoose.Schema;
      const moment = require('moment');

      const tickerSchema = new Schema({
        createdAt: { type: Date },
        updatedAt: { type: Date },
        symbol: { type: String },
        latestPrice: { type: String }
      });

      tickerSchema.pre('save', function (next) {
        let ticker = this;

        this.createdAt = ticker.createdAt ? ticker.createdAt : moment().local();
        this.updatedAt = moment().local();

        next();
      })

      Ticker = conn.model('Ticker', tickerSchema);

When I called my schema methods in a separate file, it never shared the connection.

1 Comment

Congrats on answering your own SO question! Thanks for sharing what your findings.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.