Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strange behavior with Mongoose #70

Closed
lopezjurip opened this issue Dec 20, 2016 · 9 comments
Closed

Strange behavior with Mongoose #70

lopezjurip opened this issue Dec 20, 2016 · 9 comments

Comments

@lopezjurip
Copy link

Trying mongoose with context.callbackWaitsForEmptyEventLoop = false so the function should end after calling callback(...) works different while using serverless-webpack as a plugin and when manually packing the project with webpack.

// webpack.config.js
module.exports = {
  entry: './handler.js',
  target: 'node',
  output: {
    libraryTarget: 'commonjs',
    path: 'dist',
    filename: 'handler.js',
  },

  // Any module with native extensions has to be excluded
  externals: [
    'mongoose',
  ],
}
// handler.js
'use strict';
import mongoose from 'mongoose';
import Promise from 'bluebird';

export const UserSchema = new mongoose.Schema({
  name: String,
});
const User = mongoose.model('User', UserSchema);

const MONGO_URI = process.env.MONGO_URI || 'mongodb://localhost/lambda';
mongoose.connect(MONGO_URI);

module.exports.handler = (event, context, callback) => {
  context.callbackWaitsForEmptyEventLoop = false
  return User.find({})
    .then(results => callback(null, results))
    .catch(callback);
};

With serverless-webpack

# serverless.yml
service: users

plugins:
  - serverless-webpack

custom:
  webpackIncludeModules: true

functions:
  index:
    handler: handler.handler
    events:
      - http:
          path: users
          method: get

When calling the function it gets stuck on some event-loop and eventually it times-out on AWS.

Without serverless-webpack

# serverless.yml
service: users

package:
  include:
    - dist/**

functions:
  index:
    handler: dist/handler.handler
    events:
      - http:
          path: users
          method: get

Manually running webpack and:

cd dist 
echo "{}" > package.json 
npm i --save mongoose
cd ..

And then running it locally or on production it work as expected.

@hassankhan
Copy link
Contributor

hassankhan commented Dec 25, 2016

This is more likely to do with connection pooling than with this package. Check Mongoose's docs for how to drain/close the pool, there usually is a way. Does it work without Webpack in production?

@diit
Copy link

diit commented Dec 25, 2016

Had a very similar issue that drove me insane, was fixed it for me was to close the Mongo db connection.
mongoose.disconnect()

@lopezjurip
Copy link
Author

Note context.callbackWaitsForEmptyEventLoop = false, when disabled it finish even if the connection is live. The problem that is the same code works different with and without webpack.

@pixeldrew
Copy link

I would use the native Promise on 6.10 as there are other threads with a similar issue.

@ed-zm
Copy link

ed-zm commented Jun 9, 2017

Any solution for this?

@HyperBrain
Copy link
Member

HyperBrain commented Jul 7, 2017

If you set context.callbackWaitsForEmptyEventLoop = false and use the callback you must not return anything from the handler. In your case the .then() will execute the callback correctly BUT it will also return a promise (even if the promise is resolved to undefined).

That might lead to races in AWS' Lambda code (does the callback get fired first, or does the returned promise resolve first?). AWS Lambda supports returning promises from handlers instead of using the callbacks since a while.

A safe and correct implementation would be:

module.exports.handler = (event, context, callback) => {
  context.callbackWaitsForEmptyEventLoop = false;
  User.find({})
    .then(results => callback(null, results))
    .catch(callback);
  return;   // The callback is used so nothing must be returned
};

It might be that using the plugin or using webpack externally creates slightly different code with different timing behavior.

@HyperBrain
Copy link
Member

@mrpatiwi Is this issue still valid? In the meantime 3.0.0-rc.2 is already available. If you don't mind you can try it.

@HyperBrain
Copy link
Member

Closing the issue as there has been no feedback. Feel free to reopen it or create a new one for the most current version if the issue still persists.

@edjroz
Copy link

edjroz commented Jun 6, 2018

@HyperBrain I'm also having this issue. Has anyone found any solution ?

handler.js

import 'babel-polyfill';

import { createInsertDocHandler } from './handlers';
import createRepository from './repositories/mongodb';

const db = createRepository(process.env.DB_URL);

exports.insertDoc = createInsertDocHandler(db);

handlers/index.js

import debug from 'debug';
import dummyModel from '../util/models/dummy';
import responseWrapper from '../util/responseWrapper';


const mapBodyResponse = ({ _id, name }) => ({ _id, name });

export const createInsertDocHandler = db => async (event, context, callback) => {
  debug('function:req:params')(event.pathParameters);
  debug('function:req:body')(JSON.parse(event.body));

  context.callbackWaitsForEmptyEventLoop = false;

  const document = await db
    .insert(dummyModel, query)
    .then(doc => doc)
    .catch(e => callback);
  debug('function:res')(document);
 
 return callback(null, document);
}

repositories/mongodb.js

import mongoose from 'mongoose';

const createRepository = url => {
  mongoose.connect(url).connect;
  return {
    insert: async (model, query) => model.create(query),
  };
};

export default createRepository;

I have debugged the deployed version of this function and the insertion operation is being carried away however I'm receiving a 500

whilst performing with rerverless-offline I get this warning
Warning: handler 'insertDocument' returned a promise and also use a callback! This is problematic and might cause issues in you lambda.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants