How can I use slack api in aws lambda? - node.js

I want to use IncomingWebhook api of #slack/client in aws lambda function. There is something problems in my code. Please notice me how can I use.
This is my code below
const { IncomingWebhook } = require('#slack/client');
const config = require('./config')
exports.handler = (event, context, callback) => {
const webhook = new IncomingWebhook(config.slack.webHookUrl)
webhook.send('Hello there', function(err, res) {
if (err) {
console.log('Error:', err);
context.fail('fail')
} else {
console.log('Message sent: ', res);
context.succeed('succeed')
}
});
}
And This is my errors
{
"errorMessage": "RequestId: 9e1b4362-259d-11e8-b422-91108e46ebe1
Process exited before completing request"
}
Here is console errors
START RequestId: 9e1b4362-259d-11e8-b422-91108e46ebe1 Version: $LATEST
2018-03-12T02:32:33.215Z 9e1b4362-259d-11e8-b422-91108e46ebe1 TypeError: Cannot set property 'text' of undefined
at IncomingWebhook.send (/var/task/node_modules/#slack/client/dist/IncomingWebhook.js:26:26)
at exports.handler (/var/task/index.js:6:11)
END RequestId: 9e1b4362-259d-11e8-b422-91108e46ebe1
REPORT RequestId: 9e1b4362-259d-11e8-b422-91108e46ebe1 Duration: 85.31 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 31 MB
RequestId: 9e1b4362-259d-11e8-b422-91108e46ebe1 Process exited before completing request

This was due to a bug in the Slack client which was reported here: https://github.com/slackapi/node-slack-sdk/issues/479, and subsequently fixed in https://github.com/slackapi/node-slack-sdk/releases/tag/v4.0.1. A simple upgrade to the latest version (v4.3.1 at the time of writing) will fix this.

Related

Random Instant Serverless Function Timeouts

We've been dealing with this issue in our t3 application for over a week now. Here is the error we are getting in the Vercel function logs: 
START RequestId: 3e875969-afce-4409-a7ae-96efc99ff603 Version: $LATEST 2023-01-31T13:43:45.065Z d22a6e7d-0ef6-4aa2-828e-ab70ceb99f02 ERROR Unhandled Promise Rejection  {\"errorType\":\"Runtime.UnhandledPromiseRejection\",\"errorMessage\":\"Error: timeout of 3000ms exceeded\",\"trace\":[\"Runtime.UnhandledPromiseRejection: Error: timeout of 3000ms exceeded\",\" at process.<anonymous> (file:///var/runtime/index.mjs:1194:17)\",\" at process.emit (node:events:525:35)\",\" at process.emit (node:domain:489:12)\",\" at emit (node:internal/process/promises:149:20)\",\" at processPromiseRejections (node:internal/process/promises:283:27)\",\" at process.processTicksAndRejections (node:internal/process/task_queues:96:32)\"]} [ERROR] [1675172625066] LAMBDA_RUNTIME Failed to post handler success response. Http response code: 400. RequestId: 3e875969-afce-4409-a7ae-96efc99ff603 Error: Runtime exited without providing a reason Runtime.ExitError END RequestId: 3e875969-afce-4409-a7ae-96efc99ff603 REPORT RequestId: 3e875969-afce-4409-a7ae-96efc99ff603. Duration: 12.50 ms Billed Duration: 13 ms Memory Size: 1024 MB Max Memory Used: 143 MB"
This only happens to Vercel deployed branches.Notice how it says that it is a 3000ms timeout error but the duration is only 12.50ms.
More details:
All necessary variables (like required user id's for API calls) are provided
The failing API calls succeed most of the time but about 1/5 times they fail.
Includes all our API calls
Example failing API call:
import type { NextApiRequest, NextApiResponse } from "next";
import { prisma } from "../../../server/db/client";
export default async function handler(  
req: NextApiRequest,  res: NextApiResponse) {  
if (req.method === "POST") {    
try {      
const data = JSON.parse(req.body);      
const update = await prisma.user.update({
        where: { id: data.id },
        data: data.data,      
});      
res.json(update);    
} catch (e: any) {      
res.status(500).json({ message: e.message });      
throw new Error("Could't update user:"+ e.message)
    }  
}
}
Note:
The error messages in the catch block are printed nowhere.This is more or less how we call all our serverless functions:
async function updateUserCurrentInstitution({ userId, institutionId }) {  
const response = await fetch(api.updateUser, {
    method: "POST",
    body: JSON.stringify({
      id: userId,
      data: {
        currentInstitution: institutionId,
      },
    }),
  });
  if (!response.ok) {
    throw new Error(response.statusText);
  }
  return response;
}
Any help would be greatly appreciated !

Lambda timeout after 10s both in serverless offline and online

I am new to lambda, mongodb and nodejs and I'm trying to access a mongodb database follwoing this tutorial: [pretty nice tutorial][1] . This is my second attempt at connecting to mongodb and after spending hours setting things up I run into an unsurmountable wall and none of all the answers on stack overflow have helped. Any help will be greatly appreciated.
I have inserted console.log instructions and they both are executed so the timout happens after connecting to the database, but after that I don't know what is executed. I have also set up VPC properly in AWS Lambda so I have no idea why this is timing out. ( See edit below) It might be worth mentioning that I have never been able to get past this stage: of all the things I have tried there is always a timeout error.
I have a handler.js file which, among other functions, has this one:
'use strict';
require('dotenv').config({ path: './variables.env' });
const connectToDatabase = require('./db');
const Note = require('./models/Note');
module.exports.create = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
console.log("here1");
connectToDatabase()
.then(() => {
Note.create(JSON.parse(event.body))
.then(note => callback(null, {
statusCode: 200,
body: JSON.stringify(note)
}))
.catch(err => callback(null, {
statusCode: err.statusCode || 500,
headers: { 'Content-Type': 'text/plain' },
body: 'Could not create the note.'
}));
});
console.log("here2");
};
I also have a db.js file and a Note.js file as instructed in the tutorial ( here posted respectively )
//file db.js
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
let isConnected;
module.exports = connectToDatabase = () => {
if (isConnected) {
console.log('=> using existing database connection');
return Promise.resolve();
}
console.log('=> using new database connection');
return mongoose.connect(process.env.DB)
.then(db => {
isConnected = db.connections[0].readyState;
});
};
//file Note.js
const mongoose = require('mongoose');
const NoteSchema = new mongoose.Schema({
title: String,
description: String
});
module.exports = mongoose.model('Note', NoteSchema);
Both serverless offline and serverless online give me a timeout error:
Serverless offline:
here1
=> using new database connection
here2
✖ Lambda timeout.
Serverless online:
START RequestId: f75c6e23-84e2-485c-8fb4-065a95bbbb9b Version: $LATEST
2022-10-25T11:53:44.171Z f75c6e23-84e2-485c-8fb4-065a95bbbb9b INFO here1
2022-10-25T11:53:44.171Z f75c6e23-84e2-485c-8fb4-065a95bbbb9b INFO => using new database connection
2022-10-25T11:53:44.311Z f75c6e23-84e2-485c-8fb4-065a95bbbb9b INFO here2
END RequestId: f75c6e23-84e2-485c-8fb4-065a95bbbb9b
REPORT RequestId: f75c6e23-84e2-485c-8fb4-065a95bbbb9b Duration: 10013.48 ms Billed Duration: 10000 ms Memory Size: 128 MB Max Memory Used: 100 MB Init Duration: 864.37 ms
2022-10-25T11:53:54.174Z f75c6e23-84e2-485c-8fb4-065a95bbbb9b Task timed out after 10.01 seconds
I am sending this JSON POST request through Insomnia:
{
"title":"some title",
"description": "some description"
}
After changing the timeout time to 5 mins, I am getting an error related to the connection to mongo saying I should whitelist my IP. It is whitelisted but I will investigate.
[1]: https://medium.com/hackernoon/building-a-serverless-rest-api-with-node-js-and-mongodb-2e0ed0638f47

Mongoose Unexpected token u in JSON at position 0

I'm creating an AWS Lambda API with Node JS. There's a template for the db connection itself, but when I run a test in Lambda I get an error and I believe the problem is the connection itself.
Here's the error message I get with Lambda test:
START RequestId: 6b9eef97-9c54-44bc-8ecc-dfbec7e200e5 Version: $LATEST
2020-05-23T01:46:23.685Z 6b9eef97-9c54-44bc-8ecc-dfbec7e200e5 INFO => using new database connection
2020-05-23T01:46:23.689Z 6b9eef97-9c54-44bc-8ecc-dfbec7e200e5 ERROR (node:8) DeprecationWarning: current URL string parser is deprecated, and will be removed in a future version. To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect.
2020-05-23T01:46:23.726Z 6b9eef97-9c54-44bc-8ecc-dfbec7e200e5 ERROR (node:8) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
2020-05-23T01:46:23.828Z 6b9eef97-9c54-44bc-8ecc-dfbec7e200e5 ERROR Unhandled Promise Rejection {"errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"SyntaxError: Unexpected token u in JSON at position 0","reason":{"errorType":"SyntaxError","errorMessage":"Unexpected token u in JSON at position 0","stack":["SyntaxError: Unexpected token u in JSON at position 0"," at JSON.parse ()"," at /var/task/handler.js:17:22"," at processTicksAndRejections (internal/process/task_queues.js:97:5)"]},"promise":{},"stack":["Runtime.UnhandledPromiseRejection: SyntaxError: Unexpected token u in JSON at position 0"," at process. (/var/runtime/index.js:35:15)"," at process.emit (events.js:310:20)"," at processPromiseRejections (internal/process/promises.js:209:33)"," at processTicksAndRejections (internal/process/task_queues.js:98:32)"]}
END RequestId: 6b9eef97-9c54-44bc-8ecc-dfbec7e200e5
REPORT RequestId: 6b9eef97-9c54-44bc-8ecc-dfbec7e200e5 Duration: 186.61 ms Billed Duration: 200 ms Memory Size: 1024 MB Max Memory Used: 34 MB
Unknown application error occurred
DB.js
const mongoose = require("mongoose");
mongoose.Promise = global.Promise;
let isConnected;
module.exports = connectToDatabase = () => {
if (isConnected) {
console.log("=> using existing database connection");
return Promise.resolve();
}
console.log("=> using new database connection");
return mongoose.connect(process.env.DB).then((db) => {
isConnected = db.connections[0].readyState;
});
};
Handler.js
"use strict";
const connectToDatabase = require("./db");
const Lead = require("./leads.model.js");
require("dotenv").config({ path: "./variables.env" });
module.exports.hello = (event, context, callback) => {
console.log("Hello World");
callback(null, "Hello World");
};
module.exports.create = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
connectToDatabase().then(() => {
Lead.create(JSON.parse(event.body))
.then((lead) =>
callback(null, {
statusCode: 200,
body: JSON.stringify(lead),
})
)
.catch((err) =>
callback(null, {
statusCode: err.statusCode || 500,
headers: { "Content-Type": "text/plain" },
body: "Could not create the lead.",
})
);
});
};
variables.env
DB=mongodb+srv://dbUser:password#api-jodqc.mongodb.net/test?retryWrites=true&w=majority
Whenever I see Unexpected token u in JSON at position 0, it usually means JSON.parse is trying to parse undefined. Looking at the code, I only see you executing parse in one spot
Lead.create(JSON.parse(event.body))
I'm guessing when you execute the Lambda, you're passing in an object that looks like a lead directly, so maybe something like below.
{
isALead: true
}
Instead, you need to test with an object that looks like
{
body: "{ \"isALead\": true }"
}

Problems in nodejs callback in custom alexa skill

I am trying to create a custom Alexa skill in which I am calling an API. But somehow my code is behaving weird.
CASE - 1
'firstChance': function () {
// Some code here//
getJSON(options, function (err, result) {
if (err) {
return console.log('ERROR while trying to get country names', err);
}
console.log(result);
});
this.emit(':tell', speechOutput, speechOutput);
},
In this case no errors are shown in cloudwatch but the control is not going to getJSON function eventhough this.emit() function is executed.
Below are the cloudwatch logs:
CloudWatch logs:

13:42:49
START RequestId: ************ Version: $LATEST

13:42:49
2018-04-03T13:42:49.578Z *************** Warning: Application ID is not set

13:42:49
END RequestId: *********************

13:42:49
REPORT RequestId: ************** Duration: 74.03 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 48 MB

13:42:51
START RequestId: ***************** Version: $LATEST

13:42:51
2018-04-03T13:42:51.647Z *********************** Warning: Application ID is not set

13:42:51
END RequestId: *************************

13:42:51
REPORT RequestId: ************************ Duration: 153.09 ms Billed Duration: 200 ms Memory Size: 128 MB Max Memory Used: 49 MB
CASE 2 :
'firstChance': function () {
// Some code here//
getJSON(options, function (err, result) {
if (err) {
return console.log('ERROR while trying to get country names', err);
}
console.log(result);
});
//this.emit(':tell', speechOutput, speechOutput);
},
In this case even though there are no errors in the logs and the control is going to getJSON, but alexa says "There was a problem with the requested skill's response".
Below are the cloudwatch logs:

13:35:32
START RequestId: ************************** Version: $LATEST

13:35:32
2018-04-03T13:35:32.896Z e16ddc70-3743-11e8-bf3b-a98fb0c89baf Warning: Application ID is not set

13:35:32
END RequestId: **************************

13:35:32
REPORT RequestId: ************************** Duration: 110.81 ms Billed Duration: 200 ms Memory Size: 128 MB Max Memory Used: 48 MB

13:35:35
START RequestId: ************************** Version: $LATEST

13:35:35
2018-04-03T13:35:35.549Z ************************** Warning: Application ID is not set

13:35:35
2018-04-03T13:35:35.861Z ************************** Response from Server started

13:35:35
2018-04-03T13:35:35.861Z ************************** Server Status: 200

13:35:35
2018-04-03T13:35:35.861Z ************************** Response Headers : {"server":"Cowboy","connection":"close","x-powered-by":"Express","content-type":"application/json; charset=utf-8","content-length":"187238","etag":"W/\"Vhlms2jCBxpTPF7sp9mxAw==\"","vary":"Accept-Encoding","date":"Tue, 03 Apr 2018 13:35:35 GMT","via":"1.1 vegur"}

13:35:35
2018-04-03T13:35:35.978Z ************************** Preparing the hash map...

13:35:36
2018-04-03T13:35:35.978Z ************************** [ { name: { common: 'Afghanistan', official: 'Islamic Republic of Afghanistan', native: [Object] }, tld: [ '.af' ], cca2: 'AF', ccn3: '004', cca3: 'AFG', currency: [ 'AFN' ], callingCode: [ '93' ], capital: 'Kabul', altSpellings: [ 'AF', 'Afġānistān' ], relevance: '0', region:

13:35:36
END RequestId: **************************

13:35:36
REPORT RequestId: ************************** Duration: 1249.65 ms Billed Duration: 1300 ms Memory Size: 128 MB Max Memory Used: 57 MB

13:35:36
START RequestId: ************************** Version: $LATEST

13:35:36
2018-04-03T13:35:36.954Z e46c4ff4-3743-11e8-a19e-036de9469172 Warning: Application ID is not set

13:35:36
END RequestId: **************************

13:35:36
REPORT RequestId: ************************** Duration: 1.97 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 57 MB
I am not able to resolve this.
I think, I have made some mistake in the callback of getJSON().
It looks like getJSON is an asynchronous function: meaning it returns immediately and it calls you back when the results are ready, or when an error is thrown.
So, in your example, getJSON is invoked, but it returns immediately, followed by your call to this.emit(':tell') which ends your handler and sends the respobse back to Alexa before getJSON has a chance to complete and call your anonymous function callback.
To solve, move this.emit(...) inside the callback function you are passing into getJSON
getJSON(options, function (err, result) {
if (err) {
// handle the error
this.emit(':tell', 'Error getting country names');
return console.log('ERROR while trying to get country names', err);
}
console.log(result);
// handle the successful result
this.emit(':tell', 'The country name was retrieved!');
});
Either try this,
'firstChance': function () {
// Some code here//
getJSON(options, function (err, result) {
if (err) {
return console.log('ERROR while trying to get country names', err);
}
console.log(result);
this.emit(':tell', speechOutput, speechOutput);
});
},
Or you can use set timeout :
'firstChance': function () {
// Some code here//
getJSON(options, function (err, result) {
if (err) {
return console.log('ERROR while trying to get country names', err);
}
console.log(result);
});
setTimeout(() => {
this.emit(':tell', speechOutput, speechOutput);
}, 2500)
},
Or you can try Async - Await which are now natively available in AWS Lambda as mentioned here https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/

AWS Lambda and Redis

I'm trying to write an AWS Lambda function which uses redis(on amazon elasticcache). The problem – I can't connect to redis. I use code like this
'use strict'
function handler (data, context, cb) {
const redis = require("redis")
console.log('before client initialization')
const client = redis.createClient({
url: 'redis://propper-url-cache.some.0001.euw1.cache.amazonaws.com:6379',
retry_strategy: function(options) {
console.log(options)
if (options.total_retry_time > 1000) {
throw new Error('can`t connect to redis')
}
}
})
console.log('after client initialization')
client.on("error", function (err) {
console.log('in error')
cb({error: err})
});
client.get("counter", function (err, counter) {
console.log('counter', counter)
if(_.isNull(counter)) {
counter = 0
}
client.set('counter', counter + 1, function(err) {
console.log(err)
cb(null, {counter: counter})
})
});
}
exports.handler = handler
as a result I see something like this in logs:

15:33:41
START RequestId: d8024ec2-7f36-11e6-996c-1bfcb60572c6 Version: $LATEST

15:33:42
2016-09-20T13:33:42.632Z d8024ec2-7f36-11e6-996c-1bfcb60572c6 before client initialization

15:33:42
2016-09-20T13:33:42.813Z d8024ec2-7f36-11e6-996c-1bfcb60572c6 after client initialization

15:33:44
END RequestId: d8024ec2-7f36-11e6-996c-1bfcb60572c6

15:33:44
REPORT RequestId: d8024ec2-7f36-11e6-996c-1bfcb60572c6 Duration: 3002.67 ms Billed Duration: 3000 ms Memory Size: 128 MB Max Memory Used: 19 MB

15:33:44
2016-09-20T13:33:44.620Z d8024ec2-7f36-11e6-996c-1bfcb60572c6 Task timed out after 3.00 seconds
when I change redis url for something which definitely makes no sense I have an additional row:
2016-09-20T13:29:42.953Z 48fcb071-7f36-11e6-bc52-c5ac58c12843 { attempt: 1, error: { [Error: Redis connection to some-url.euw1.cache.amazonaws.com:6379 failed - getaddrinfo ENOTFOUND some-url.euw1.cache.amazonaws.com some-url.euw1.cache.amazonaws.com:6379] code: 'ENOTFOUND', errno: 'ENOTFOUND', syscall: 'getaddrinfo', hostna
Any ideas?
You need to have Redis in same VPC as Lambda. Check your security group settings. And then if you have EC2 access, install redis-cli and try to connect Redis. If this get connected your Lambda Redis will also get connected. As said earlier, you need to have your lambda in same VPC.
The following is boilerplate code demonstrating connecting to Lambda:
console.log('before client initialization')
const redisOptions = {
host: 'xxxx.xxx.xxx.xxx.xxx.amazonaws.com',
port: 6379,
}
var client = redis.createClient(redisOptions);
console.log('after client initialization');
client.on('connect', function(result) {
console.log('connected');
}

Resources