question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Discussion: Running Bolt apps on Function-as-a-Service

See original GitHub issue

Description

Disclaimer

Creating this issue doesn’t mean the Bolt team is going to provide a proper way to support FaaS (e.g., AWS Lambda, Google Cloud Functions, Cloud Functions for Firebase, etc.) in the short run.

I wanted to create a place to discuss any future possibilities to support FaaS in some ways.

The challenge we have with FaaS

One limitation you should know when you run Bolt apps on FaaS is that any asynchronous operations can be silently terminated once its internet-facing function responds to an incoming HTTP request from Slack.

Examples of “asynchronous operations” here are say, respond, app.client calls, and whatever internally starts Promise operations separately from ack() completion.

Let’s say you want to create an AWS Lambda function that is free from Slack’s 3-second timeouts and the limitation I mentioned above. In this case, the following code is a solution.

const { App, ExpressReceiver } = require('@slack/bolt');
import AWS = require('aws-sdk');

const receiver = new ExpressReceiver({
  signingSecret: process.env.SLACK_SIGNING_SECRET
});
const app = new App({
  receiver,
  token: process.env.SLACK_BOT_TOKEN,
});

app.command("/hello", ({ body, ack }) => {
  if (isLocalDevelopment()) {
    ack();
    mainLogic(body);
  } else {
    const lambda = new AWS.Lambda();
    const params: AWS.Lambda.InvocationRequest = {
      InvocationType: 'Event', // async invocation
      FunctionName: functionName,
      Payload: JSON.stringify(body)
    };
    const lambdaInvocation = await lambda.invoke(params).promise();
    // check the lambdaInvocation here
    ack();
  }
});

function mainLogic(body) {
  // do something it may take a long time
}

// frontend: internet-facing function handling requests from Slack
const awsServerlessExpress = require('aws-serverless-express');
const server = awsServerlessExpress.createServer(receiver.app);
module.exports.frontend = (event, context) => {
  awsServerlessExpress.proxy(server, event, context);
}

// backend: internal function for anything apart from acknowledging requests from Slack
module.exports.backend = async function (event, _context) {
  // if you reuse this function for other patterns, need to dispatch the events
  await mainLogic(event);
  return {
    statusCode: 200,
    body: JSON.stringify({ message: 'done' }),
  };
};

One possible idea I came up with

Let me refer to my comment in another issue: https://github.com/slackapi/bolt/issues/353#issuecomment-568811051

One feasible idea is creating a FaaS support package as a 3rd-party one. That means the package won’t be managed by @slackapi. The authors of such packages can be anyone. If someone starts such projects, I’ll be more than happy to support them.

As a first step, I’ll publish my prototype implementation in my own repository and will start a new GitHub issue in this repository. I hope it will be a good starting point for people interested in FaaS support. Even though my prototype is still in very alpha quality, checking it could be helpful for the folks that may start new projects.

If Bolt changes its APIs and internals, it may be feasible to have a 3rd-party generalized npm package that offers proper FaaS supports for Bolt.

Here is my prototype demonstrating it: https://github.com/seratch/bolt-aws-lambda-proof-of-concept It doesn’t support all the features yet but it just works for supported cases.

Here is a simple example code (just pasted from the repository’s README).

const app = new TwoPhaseApp({
  token: process.env.SLACK_BOT_TOKEN,
  // this receiver tries to get AWS credentials from env variables by default
  receiver: new AwsLambdaReceiver({
    signingSecret: process.env.SLACK_SIGNING_SECRET
  })
});

app.command('/lambda')
  .ack(({ ack }) => {
    // phase1 function: compatible with current listener function
    ack('ack response');
  })
  .then(async ({ body, say }) => {
    // phase2 function: this one is invoked as another lambda function
    return say('How are you?').then(() => say("I'm good!"));
  });

Now developers don’t need to directly use AWS Lambda SDK. AwsLambdaReceiver does everything for you: https://github.com/seratch/bolt-aws-lambda-proof-of-concept/blob/7b72a5e416977036e98c4bfbf40ee0567910766c/src/added/AwsLambdaReceiver.ts#L174-L189

Apart from the things specific to AWS, this approach is applicable to any others (not only FaaS).

In this design, the two phases are:

  • Phase 1: internet-facing handler - responsible for request acknowledgment and synchronous things (e.g., signature verification, dispatching requests, payload validation, and responding a message as part of HTTP responses)
  • Phase 2: internal function - can do anything with the relayed request body asynchronously / use respond to send a message to a user asynchronously

Phase 2 function is supposed to return a single Promise as its result. The design makes easier to write code in idiomatic ways (like using then/catch and/or Promise.all) for working with Promises.

Next steps

If someone is interested in starting with my PoC prototype to build a 3rd-party library, I’m happy to donate my code (it’s under the MIT license) and will be more than happy to contribute to it as an individual.

To realize such 3rd parties, a few changes on the Bolt side are still needed. @aoberoi shared a related proposal at https://github.com/slackapi/bolt/issues/353. Join the conversation to share your thoughts and/or feedback.

What type of issue is this? (place an x in one of the [ ])

  • bug
  • enhancement (feature request)
  • question
  • documentation related
  • testing related
  • discussion

Requirements (place an x in each of the [ ])

  • I’ve read and understood the Contributing guidelines and have done my best effort to follow them.
  • I’ve read and agree to the Code of Conduct.
  • I’ve searched for any related issues and avoided creating a duplicate issue.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:9
  • Comments:6 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
threesquaredcommented, Jan 10, 2020

If it helps at all I had some success running Bolt on Lambda in this app by using the express receiver and aws-serverless-express. It seems to work as intended but has not been extensively tested.

1reaction
seratchcommented, Jan 10, 2020

@threesquared Thanks for your comment. Yes, for simple apps, it works mostly. If a Bolt app has time-consuming Promises, those operations may be unexpectedly terminated. The current Bolt implementation doesn’t offer a proper way to deal with the problem.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Bolt for Python - Slack Platform Developer Tools
A framework that makes Slack app development fast and straight-forward. With a single interface for Slack's Web API, Events API, and interactive features, ......
Read more >
Building an app with Bolt for JavaScript - Slack API
Bolt for JavaScript. Bolt is a foundational framework that makes it easier to build Slack apps with the platform's latest features. This guide...
Read more >
Bolt (@boltapp) / Twitter
Open your Bolt app and jump down the rabbit hole of your 2022 highlights. ... The first event in the live discussion series...
Read more >
Managing apps running in the background - HTC Bolt
This site uses cookies to optimize website functionality, analyze website performance, and provide personalized experience and advertisement.
Read more >
@slack/bolt - npm
A JavaScript framework to build Slack apps in a flash with the latest platform features. Read the getting started guide to set-up and...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found