I'm using AWS Lambdas to try and connect to a CMS and i've encountered the following error:
Process exited before completing request
Here's my snippet below:
require('dotenv').config({ silent: true });
const contentful = require('contentful');
exports.handler = (event, context) => {
const client = contentful.createClient({
space: process.env.SPACE_ID,
accessToken: process.env.CDA_TOKEN
})
client.getEntries({
'content_type': 'thumbnail'
})
.then(function (entries) {
context.succeed(JSON.stringify(entries));
})
};
Does this error suggest that i'm getting an error somewhere in my code that's preventing it from running context.succeed or that i'm using context.succeed incorrectly?
Process exited before completing request
It means that you got an unhandled exception. Your handler basically crashed without telling Lambda why.
Looking at your code, it is most likely that the client.getEntries() promise got rejected and you didn't provide a .catch() to your promise.
You can do the following instead...
// Use callback coz context.succeed() is soooo legacy.
exports.handler = (event, context, callback) => {
const client = contentful.createClient({
space: process.env.SPACE_ID,
accessToken: process.env.CDA_TOKEN
})
return client.getEntries({
'content_type': 'thumbnail'
})
// Be consistent with arrow function usage.
.then((entries) => callback(null, JSON.stringify(entries)))
// This is what is missing.
.catch((err) => {
// Log the error so you know what it is and fix it.
console.error(err);
// Be polite and tell Lambda that the invocation failed.
callback(err);
});
};
Related
I've built a simple script to detect if a port is opened/closed on my machine. I've successfully make it work using the old-fashion callback way, but can't make it work with Promise (async/await).
Any clue why the two scripts below are not working exactly the same? Using callbacks, it works neat. Using Promise (async/await) it crash by throwing an "uncaughtException" error.
✅ Using callbacks
const net = require('node:net')
/**
* Connect to port with callback
*/
function connectToPort(port, callback) {
const client = net.connect(port, 'localhost', function () {
callback(true)
})
client.on('error', function (err) {
callback(err)
})
}
/**
* Connect
*/
async function test(port) {
console.log(`Trying to connect to port "${port}"...`)
// Connect with callback
connectToPort(port, function (result) {
console.log({ port, open: result === true })
})
}
// Output:
// Trying to connect to port "4242"...
// { port: 4242, open: false }
test(4242)
❌ Using Promise (async/await)
const net = require('node:net')
/**
* Connect to port with Promise
*/
function asyncConnectToPort(port) {
return new Promise(function (resolve, reject) {
const client = net.connect(port, 'localhost', function () {
resolve(true)
})
client.on('error', function (err) {
reject(err)
})
})
}
/**
* Connect
*/
async function test(port) {
console.log(`Trying to connect to port "${port}"...`)
// Connect with promise
const result = await asyncConnectToPort(port)
console.log({ port, open: result === true })
}
// Output:
// Trying to connect to port "4242"...
// Error: connect ECONNREFUSED 127.0.0.1:4242
test(4242)
Both scripts look exactly the same to me. Apparently, the "error" event must be present to avoid Nodejs to throw an "uncaughtException". That "special" event is detected when using callback, but I suspect it's not with Promise. Could it be something behind the scene that differs when working with await/async script?
An error event is raised in both your code examples.
In the Promise code that you wrote you pass that error event to reject().
When you call reject you raise an exception.
Hence, you get an exception in your Promise based code but not in the other code. You added one!.
Handling it is a case of:
try {
const result = await asyncConnectToPort(port)
console.log({ port, open: result === true })
} catch (e) {
// do something with e here
}
However a Promise can only be settled once.
The code you've written will call resolve when the callback to net.connect runs and it will call reject on an error event but these are not mutually exclusive.
It's possible for your code to end up calling both resolve and reject, and also for it to call reject multiple times.
I'm trying to turn off unhandled promise rejection on my discord.js bot that uses an event handler, I've found this online on how to do it, but it doesn't seem to work with my event handler: solution I've found online.
Here's my event handler:
fs.readdir('./events/', (err, files) => {
files.forEach(file => {
const eventHandler = require(`./events/${file}`)
const eventName = file.split('.')[0]
client.on(eventName, arg => eventHandler(client, arg));
})
})
My event files look something like this:
const Discord = require('discord.js');
module.exports = (client) => {
//code
}
How would I implement the code in the picture into my event handler?
Right now, you aren't handling errors thrown by the discord.js library. You have a handler like:
module.exports = (client) => {
//code
}
That means that if the discord.js code throws an error, there is no code to handle the error.
You can use a few techniques to solve the problem. If you're a fan of async/await, you can change your handler to be an async function and use try/catch to handle the errors:
module.exports = async (client) => {
try {
// call discord.js code
} catch (error) {
// handle rejected promise from discord.js code
}
}
You can also use the non-async/await style of handling errors from chains of promises:
module.exports = async (client) => {
client.somePromiseIsReturned()
.then(result => {
// handle result of discord.js operation
})
.catch(error => {
// handle rejected promise from discord.js code
};
}
The technique the solution you posted uses is to handle all errors the same way, by using console.log to log the error's message. Their code is a concise way of doing that:
somePromiseIsReturned().catch(console.log);
is equivalent to:
somePromiseIsReturned().catch(error => console.log(error));
I'm trying to write a test in jest but keep getting UnhandledPromiseRejectionWarning when I try to use mockRejectedValue
The code looks like this:
it('Should set error message when call fails', async () => {
const context = mockActionsContext();
const user = {
username: 'alice',
password: 'password'
};
const getError = new Error('network error');
(AuthService.login as jest.Mock) = jest.fn().mockRejectedValue(getError);
await actions[ActionTypes.USER_LOGIN](context, user);
// Check is the commits are called
expect((context.commit as any).mock.calls).toEqual([
[MutationTypes.USER_LOGIN],
[MutationTypes.USER_LOGIN_ERROR, 'Oops, something went wrong. Try again later!']
]);
// Login service is called with user login
expect(AuthService.login as jest.Mock).toHaveBeenCalledWith(user);
});
The AuthService.login returns an axios.post which I try to overwrite with a mock.
actions[ActionTypes.USER_LOGIN](context, user) calls the Authservice.login
The test is passing but I don't want any unhandled promise rejection. Anybody an idea how to fix it?
Edit
#goodmorningasif thanks for your reply.
I've been looking at it too long I thing :)
The action looks as following:
[ActionTypes.USER_LOGIN]: ({ commit }: Context, payload: User) => {
return new Promise((resolve, reject) => {
commit(MutationTypes.USER_LOGIN);
AuthService.login(payload)
.then((token) => {
commit(MutationTypes.USER_LOGIN_SUCCESS, token);
localStorage.setItem('user-token', token);
client.defaults.headers.common.Authorization = `Bearer ${token}`;
resolve(token);
})
.catch((error) => {
let errorMessage = 'Oops, something went wrong. Try again later!';
if (error?.response?.status === 401) {
errorMessage = 'Unknown username and password combination!';
}
localStorage.removeItem('user-token');
commit(MutationTypes.USER_LOGIN_ERROR, errorMessage);
reject(error);
});
});
},
SOLUTION
In my case the action is returning a promise witch would get rejected. In the test, I'm calling the action directly and not catching the rejection.
await actions[ActionTypes.USER_LOGIN](context, user).catch(() => null);
This fixed it.
Can we see the actions and reducer code? It's possible that there's an error in your error :)
You're testing that the login function is called and the action returns the error message you set but you're making an assumption about what causes the error. Maybe it's not because of the mockRejectedValue/'network error'.
I'd suggest including the actual error message in the action payload as well as your error message: one is for developers and debugging and one is for the user to know what to do next.
I also found this helpful on understanding UnhandledPromiseRejectionWarning: https://thecodebarbarian.com/unhandled-promise-rejections-in-node.js.html
Good instinct to figure out the issue and not be content with the test passing, by the way!
I am an android developer and I am trying to use cloud functions in firebase.I set up the entire thing without understanding much of the script apart from the basic structure.
Most importantly I want to know how I can remove those warnings because I don't want it to stop working if something gets deprecated.
The warnings from the interface:
24:13 warning Unexpected function expression prefer-arrow-callback
28:16 warning Unexpected function expression prefer-arrow-callback
60:11 warning Avoid nesting promises promise/no-nesting
60:11 warning Avoid nesting promises promise/no-nesting
61:13 warning Unexpected function expression prefer-arrow-callback
65:16 warning Unexpected function expression prefer-arrow-callback
✖ 6 problems (0 errors, 6 warnings)
0 errors and 4 warnings potentially fixable with the `--fix` option
My code:
let functions = require('firebase-functions');
let admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotification = functions.database.ref("Notifications").onWrite((change, context) => {
const afterData = change.after.val(); // data after the write
console.log("after: ", afterData.topic);
console.log("after: ", afterData.msg);
const payload = {
data: {
data_type: "direct_message",
title: "New Message " ,
message: afterData.msg,
}
};
return admin.messaging().sendToTopic(afterData.topic, payload)
.then(function(response) {
console.log("Successfully sent message:", response);
return;
})
.catch(function(error) {
console.log("Error sending message:", error);
return;
});
});
exports.sendToOne = functions.database.ref("messages").onWrite((change, context) => {
const afterData = change.after.val(); // data after the write
const message = afterData.message;
const receiverid = afterData.id;
console.log("receiver id : ", receiverid);
console.log("receiver message : ", message);
return admin.database().ref("/users/"+receiverid).once('value').then(snap => {
const senderName = snap.child("name").val();
const token = snap.child("token").val();
console.log("receiver name: ", senderName);
console.log("receiver token: ", token);
console.log("Construction the notification message.");
const payload = {
data: {
data_type: "direct_message",
title: "New Message",
message: message
}
};
return admin.messaging().sendToDevice(token, payload)
.then(function(response) {
console.log("Successfully sent message:", response);
return;
})
.catch(function(error) {
console.log("Error sending message:", error);
return;
});
});
});
How do I remove these warnings, please help.
You have two kinds of warnings, prefer-arrow-callback and promise/no-nesting
prefer-arrow-callback
Like #Teemu pointed out in the comments, you just have to change your anonymous functions to arrow functions.
Based on the warning messages, the functions are in the lines 24, 28, 61 and 65, which are the majority of the then and catch in your code. You will have to refactor them to arrow functions. For example, instead of .then(function(response) { use .then((response) => {.
There are many reasons for this change, like improving readability, but I believe the most important is that this method doesn't bind the this.
You can read more about the difference between traditional anonymous functions and arrow functions here.
promise/no-nesting
In the #DougStevenson answer you linked you have the answer already. To explain it further, instead of having a promise (.then() or .catch() statement) inside another, is better to return the promise object in the first promise and call the second then() or .catch() afterwards.
In your code, the issue is that you have this nested promises:
return admin.database().ref("/users/"+receiverid).once('value').then(snap => { // Your first promise
[...]
return admin.messaging().sendToDevice(token, payload)
.then(function(response) { // Second promise
[...]
});
});
To fix this, follow #Doug's advice and call the second promise after the first, something like this:
return admin.database().ref("/users/"+receiverid).once('value').then(snap => { // Your first promise
[...]
return admin.messaging().sendToDevice(token, payload);
})
.then(function(response) { // Second promise
[...]
});
What's the correct way to throw an error from an async Mongoose middleware post hook?
Code Example
The following TypeScript code uses mongoose's post init event to run some checks that are triggered whenever a function retrieves a doc from mongoDb. The postInit() function in this example is executing some background checks. It is supposed to fail under certain circumstances and then returns a Promise.reject('Error!');
schema.post('init', function (this: Query<any>, doc: any) {
return instance.postInit(this, doc)
.catch( err => {
return err;
});
});
The hook works fine. I.e. the following code triggers the hook:
MyMongooseModel.findOne({ _id : doc.id}, (err, o : any) => {
console.log(o);
});
However, if postInit() fails, the error isn't passed back to the calling function. Instead, the document is returned.
Expected behavior
I'm looking for the right way to pass this error to the calling function. If the background checks fail, the calling function shouldn't get a document back.
I have tried different ways to raise this error. E.g. throw new Error('Error');. However, this causes an UnhandledPromiseRejectionWarning and still returns the document.
Mongoose maintainer here. Unfortunately, init() hooks are synchronous and we haven't done a good job documenting that. We opened up a GitHub issue and will add docs on that ASAP. The only way to report an error in post('init') is to throw it.
const assert = require('assert');
const mongoose = require('mongoose');
mongoose.set('debug', true);
const GITHUB_ISSUE = `init`;
const connectionString = `mongodb://localhost:27017/${ GITHUB_ISSUE }`;
const { Schema } = mongoose;
run().then(() => console.log('done')).catch(error => console.error(error.stack));
async function run() {
await mongoose.connect(connectionString);
await mongoose.connection.dropDatabase();
const schema = new mongoose.Schema({
name: String
});
schema.post('init', () => { throw new Error('Oops!'); });
const M = mongoose.model('Test', schema);
await M.create({ name: 'foo' });
await M.findOne(); // Throws "Oops!"
}
This is because Mongoose assumes init() is synchronous internally.
In this post init hook method you only receive a doc:
Document.prototype.init()
Parameters doc «Object» document returned by
mongo Initializes the document without setters or marking anything
modified.
Called internally after a document is returned from mongodb.
Mongoose Documentation: Init HookDocumentation
And for trigger a error you need a done or next method:
Post middleware
post middleware are executed after the hooked method and all of its
pre middleware have completed. post middleware do not directly receive
flow control, e.g. no next or done callbacks are passed to it. post
hooks are a way to register traditional event listeners for these
methods.
Mongoose Documentation: Post Middleware
If you only want to know if happened a error in your call, change for this:
MyMongooseModel.findOne({ _id : doc.id}, (err, o : any) => {
if(err) {
throw new Error(err);
}
console.log(o);
});
If you want to propagate the error one option is use a pre hook method:
schema.pre('save', function(next) {
const err = new Error('something went wrong');
// If you call `next()` with an argument, that argument is assumed to be
// an error.
next(err);
});
schema.pre('save', function() {
// You can also return a promise that rejects
return new Promise((resolve, reject) => {
reject(new Error('something went wrong'));
});
});
schema.pre('save', function() {
// You can also throw a synchronous error
throw new Error('something went wrong');
});
schema.pre('save', async function() {
await Promise.resolve();
// You can also throw an error in an `async` function
throw new Error('something went wrong');
});
Example Error Handling: Error Handling