Skip to content

close server after context succeed - #103

Closed
jeremygiberson wants to merge 1 commit into
CodeGenieApp:masterfrom
jeremygiberson:close-server
Closed

close server after context succeed#103
jeremygiberson wants to merge 1 commit into
CodeGenieApp:masterfrom
jeremygiberson:close-server

Conversation

@jeremygiberson

Copy link
Copy Markdown

This PR is in response to #91 an issue that our organization experiences as well.

In our case, we are using serverless framework with the "serverless-offline" plugin that spins up the service in our local environment and serves multiple requests. I think the expectation in lambda is a single request being serviced per process but in some local dev configurations a single process might be servicing multiple requests. For example we do local dredd API testing which starts serverless offline and calls all of our REST endpoints before shutting down serverless.

To recreate the issue:

  • install serverless
  • create serverless hello world template
  • install serverless-offline plugin
  • install expressjs
  • install aws-serverless-express

Serverless config

service: serverless-hello-world

# The `provider` block defines where your service will be deployed
provider:
  name: aws
  runtime: nodejs6.10

plugins:
  - serverless-offline

# The `functions` block defines what code to deploy
functions:
  helloWorld:
    handler: handler.helloWorld
    # The `events` block defines how to trigger the handler.helloWorld code
    events:
      - http:
          path: hello-world
          method: get
          cors: true

Serverless handler

'use strict';

const express = require('express');
const app = express();

app.get('/hello-world', function (req, res) {
  res.send('Hello World!')
});


const awsServerlessExpress = require('aws-serverless-express');

const server = awsServerlessExpress.createServer(app);

exports.helloWorld = (event, context, callback) => awsServerlessExpress.proxy(server, event, context);

Test your service locally:

$ sls offline start
Serverless: Starting Offline: dev/us-east-1.

Serverless: Routes for helloWorld:
Serverless: GET /hello-world

Serverless: Offline listening on http://localhost:3000

Hit your endpoint multiple times:

curl -v http://localhost:3000/hello-world
curl -v http://localhost:3000/hello-world
curl -v http://localhost:3000/hello-world

Observe warnings:

Serverless: GET /hello-world (λ: helloWorld)
Serverless: The first request might take a few extra seconds
Serverless: [200] {"statusCode":200,"body":"Hello World!","headers":{"x-powered-by":"Express","content-type":"text/html; charset=utf-8","content-length":"12","etag":"W/\"c-Lve95gjOVATpfV8EL5X4nxwjKHE\"","date":"Sun, 08 Oct 2017 19:00:36 GMT","connection":"close"},"isBase64Encoded":false}

Serverless: GET /hello-world (λ: helloWorld)
WARNING: Attempting to listen on socket /tmp/server0.sock, but it is already in use. This is likely as a result of a previous invocation error or timeout. Check the logs for the invocation(s) immediately prior to this for root cause, and consider increasing the timeout and/or cpu/memory allocation if this is purely as a result of a timeout. aws-serverless-express will restart the Node.js server listening on a new port and continue with this request.
Serverless: [200] {"statusCode":200,"body":"Hello World!","headers":{"x-powered-by":"Express","content-type":"text/html; charset=utf-8","content-length":"12","etag":"W/\"c-Lve95gjOVATpfV8EL5X4nxwjKHE\"","date":"Sun, 08 Oct 2017 19:00:37 GMT","connection":"close"},"isBase64Encoded":false}

Serverless: GET /hello-world (λ: helloWorld)
WARNING: Attempting to listen on socket /tmp/server0.sock, but it is already in use. This is likely as a result of a previous invocation error or timeout. Check the logs for the invocation(s) immediately prior to this for root cause, and consider increasing the timeout and/or cpu/memory allocation if this is purely as a result of a timeout. aws-serverless-express will restart the Node.js server listening on a new port and continue with this request.
WARNING: Attempting to listen on socket /tmp/server1.sock, but it is already in use. This is likely as a result of a previous invocation error or timeout. Check the logs for the invocation(s) immediately prior to this for root cause, and consider increasing the timeout and/or cpu/memory allocation if this is purely as a result of a timeout. aws-serverless-express will restart the Node.js server listening on a new port and continue with this request.
Serverless: [200] {"statusCode":200,"body":"Hello World!","headers":{"x-powered-by":"Express","content-type":"text/html; charset=utf-8","content-length":"12","etag":"W/\"c-Lve95gjOVATpfV8EL5X4nxwjKHE\"","date":"Sun, 08 Oct 2017 19:00:38 GMT","connection":"close"},"isBase64Encoded":false}

With the change the PR applies, we simply call close on server after context.succeed is called.

Re-run local test and hit the endpoint multiple times and observe the warning is no longer present.

Serverless: GET /hello-world (λ: helloWorld)
Serverless: The first request might take a few extra seconds
Serverless: [200] {"statusCode":200,"body":"Hello World!","headers":{"x-powered-by":"Express","content-type":"text/html; charset=utf-8","content-length":"12","etag":"W/\"c-Lve95gjOVATpfV8EL5X4nxwjKHE\"","date":"Sun, 08 Oct 2017 19:03:02 GMT","connection":"close"},"isBase64Encoded":false}

Serverless: GET /hello-world (λ: helloWorld)
Serverless: [200] {"statusCode":200,"body":"Hello World!","headers":{"x-powered-by":"Express","content-type":"text/html; charset=utf-8","content-length":"12","etag":"W/\"c-Lve95gjOVATpfV8EL5X4nxwjKHE\"","date":"Sun, 08 Oct 2017 19:03:02 GMT","connection":"close"},"isBase64Encoded":false}

Serverless: GET /hello-world (λ: helloWorld)
Serverless: [200] {"statusCode":200,"body":"Hello World!","headers":{"x-powered-by":"Express","content-type":"text/html; charset=utf-8","content-length":"12","etag":"W/\"c-Lve95gjOVATpfV8EL5X4nxwjKHE\"","date":"Sun, 08 Oct 2017 19:03:03 GMT","connection":"close"},"isBase64Encoded":false}

Serverless: GET /hello-world (λ: helloWorld)
Serverless: [200] {"statusCode":200,"body":"Hello World!","headers":{"x-powered-by":"Express","content-type":"text/html; charset=utf-8","content-length":"12","etag":"W/\"c-Lve95gjOVATpfV8EL5X4nxwjKHE\"","date":"Sun, 08 Oct 2017 19:03:03 GMT","connection":"close"},"isBase64Encoded":false}

@jeremygiberson

Copy link
Copy Markdown
Author

I have to withdraw this solution. While it works great in the serverless offline environment it fails in AWS lambda. I think I was under a misconception of how AWS lambda works. Looks like a lambda function service serves more than a single request.

Comment thread index.js

context.succeed(successResponse)
context.succeed(successResponse);
if (server && server.close) {

@scalebig scalebig Dec 9, 2017

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize this is closed, but I am dealing with the same. Thoughts using something like:
if(process.env.IS_OFFLINE) { .... }

@brettstack

Copy link
Copy Markdown
Collaborator

This is a great suggestion. If you or OP want to submit PR with this plus tests, I'll merge it in. Otherwise I'll tackle it when I can.

@scalebig

scalebig commented Dec 9, 2017

Copy link
Copy Markdown

Thx :) I will take a stab at the PR + tests when I get a moment this weekend. I have monkey patched locally for now 😞

@matttowerssonos

Copy link
Copy Markdown

@scalebig ℹ️ I applied the monkey patch you suggested and while it works locally, with it applied in an AWS context, I'm intermittently seeing the following errors in my CloudWatch logs as well as 502 errors returned to the client.

at Object.exports._errnoException (util.js:1018:11)
at exports._exceptionWithHostPort (util.js:1041:20)
at PipeConnectWrap.afterConnect [as oncomplete] (net.js:1086:14)
code: 'ECONNRESET',
errno: 'ECONNRESET',
syscall: 'connect',
address: '/tmp/server0.sock' }```

@guerrerocarlos

guerrerocarlos commented Jan 7, 2018

Copy link
Copy Markdown

I had the same problem described here when running aws-serverless-express with node-lambda so implemented this same PR together with a 'local' flag defined in node-lambda when running locally (motdotla/node-lambda#405)

I guess the same flag could also be added to serverless-offline and similar tools.

@iliasbhal

iliasbhal commented Feb 8, 2018

Copy link
Copy Markdown

Here is my workaround

I call this function before awsServerlessExpress.create()
it removes the junk file that happens to create the warning.

  function monkeyPatchAwsServerlessExpress(){
    // awsServerlessExpress keeps warning when using it on localhost
    // we will patch it in order to stop it from polluting the console
    // here is what this patch is hiding from you on each request :
  
    // WARNING: Attempting to listen on socket /tmp/server0.sock, but it is already in use. 
    // This is likely as a result of a previous invocation error or timeout. 
    // Check the logs for the invocation(s) immediately prior to this for root cause, and consider increasing the timeout and/or cpu/memory allocation if this is purely as a result of a timeout. 
    // aws-serverless-express will restart the Node.js server listening on a new port and continue with this request.
    
  
    // when using with serverless-offline
    // junk files inside tmp folder has to be cleaned up 
      
    if( process.env.IS_OFFLINE){

        let fs = require('fs')
        let createServer = awsServerlessExpress.createServer
        awsServerlessExpress.createServer = (server)=>{
          let awsExpressServer = createServer( server )
          let tmp_path = awsServerlessExpress.getSocketPath(awsExpressServer._socketPathSuffix) 
          if( fs.existsSync(tmp_path) ) { fs.unlinkSync( tmp_path ) }
          return awsExpressServer
        }
    
      }
    
  }

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

Successfully merging this pull request may close these issues.

6 participants