Send response before stopping function

Hi~

I want to use Netlify Functions to handle Slack commands but these functions will need to perform database read and write and will most likely end up exceeding the Slack 3000ms limit to give an answer (which trigger an operation_timout on the Slack side).

So in order to do so I need to send Slack an empty 200 before ending the function process which in pratice look like this:

exports.handler = async (event, context) => {
  performHeavyOperationAsynchronously(); // database read write and such

  // don't wait for previous function to end and just fire the 200 answer
  return { statusCode: 200, body: "" }; // send empty 200
}

So while this code run nicely in development (using netlify dev) when in production on Netlify it appears to not launch / keep processing what’s inside performHeavyOperationAsynchronously() (because perhaps there’s some sort of a process.exit() after the handler return answer)

Any idea how to fix that ? (or if this is even possible?) / what’s the cause of the process not keeping processing the async function after function return?

Thanks~!

Hi, @lihbr and welcome to our Netlify community site.

Does the 200 response occur but the other processing does not complete? If so, it is possible it is hitting the default 10 second timeout documented here:

https://docs.netlify.com/functions/overview/#default-deployment-options

Quoting:

By default, all serverless functions are deployed with:

  • us-east-1 AWS Lambda region
  • 1024MB of memory
  • 10 second execution limit

If the Functions plan for the site is upgraded to Level 1 (or higher) we can increase this timeout to a maximum value of 28 seconds.

​Please let us know if there are other questions and/or if you would like the timeout increased.

Hi @luke,

Yes indeed the 200 response occur but the processing that should continue further that answer is not performed, though I do not think that this has something to do with the 10 seconds timeout as what’s behind the performHeavyOperationAsynchronously() so far is just a ping back to Slack using node-fetch (fire and forget style) which last less than a second when running the same function locally with netlify dev.

Hi again,

Here’s a more concrete example of a “fire and forget” async code that does work in local with netlify dev but does not in production on Netlify (my site is this one if you want to / can check: pre-renne-2019-st4ging with the test.js function), hope that’ll help:

require("dotenv").config();
const fetch = require("node-fetch");

exports.handler = async (event, context) => {
  fetch("https://slack.com/api/chat.postMessage", {
    headers: {
      "content-type": "application/json",
      authorization: `Bearer ${process.env.SLACK_BOT_OAUTH_TOKEN}`
    },
    method: "POST",
    body: JSON.stringify({
      channel: "CQ21G28P5",
      text: "hey from netlify functions"
    })
  });

  return { statusCode: 200, body: "" };
};

Basically the return 200 works but not the previously launched async code when running production :thinking:

Hi @lihbr , You need to use the await keyword on your fetch call in order for JS to wait for it to resolve before moving on with the rest of the code.

Hi @futuregerald, thank you for your answer.

I know that if I use await the code will wait for that async load to be performed but that’s not my point here. I want to fire that async load (in my example a fetch but that could be anything else), forget about it and send back response to client directly (without waiting for that async load to end but it should be still performed in the background after the response was sent to client while remaining under the 10s limit).

As pointed out my example here work perfectly fine when used with netlify dev when developing but does not once in production~

Sorry, I didn’t understand your use-case before. The fetch call should be sent but the function won’t wait for it, this is what you intend. Can you try removing the async keyword on the function so that it doesn’t return a promise and see if that does what you intend?

Ok so apparently doing it does work when doing it the callback way (see code below), kinda weird though that the return way does not work in production as it should be the same? If you have any clue on why it changes something let me know, thanks anyway :slight_smile:

require("dotenv").config();
const fetch = require("node-fetch");

exports.handler = (event, context, callback) => {
  fetch("https://slack.com/api/chat.postMessage", {
    headers: {
      "content-type": "application/json",
      authorization: `Bearer ${process.env.SLACK_BOT_OAUTH_TOKEN}`
    },
    method: "POST",
    body: JSON.stringify({
      channel: "CQ21G28P5",
      text: "hey from netlify functions"
    })
  });

  callback(null, { statusCode: 200, body: "" });
};

As far as I can tell, the ‘return’ syntax is meant only for async lambda functions and that if you don’t intend to return a promise, then you’ll want to use a callback instead. In any case, I’m glad you found a solution that works for you.