I have the following code to read a file from a URL and then upload it to another destination:
import request from 'request';
import FormData from 'form-data';
export const handler = async (event, context) => {
new Promise((resolve, reject) => {
const form = new FormData();
console.log('Streaming ...');
form.append('file', request('https://cdn.mysite.com/video.mp4'));
console.log('Uploading ...');
// Invocation ends here!
form.submit('https://www.someapi.com/upload', (error, response) => {
if (error) reject(error);
let body = '';
response.on('data', chunk => {
console.log('Receiving response ...');
body = chunk.toString()
});
response.on('end', () => {
console.log('Done ...');
resolve(JSON.parse(body))
});
response.resume();
});
});
};
Running this code locally works fine, but when I deploy and run it on AWS Lambda it ends before submitting the form. I tried to remove the Promise and run the code inside it but got the same result!
I don't know if it starts the submission or not, but the last thing I see on the cloud logs is Uploading ...
, and the invocation ends after it immediately.
How to make the Lamda function waits until the promise is resolved?
CodePudding user response:
This is missing a return
statement as mentioned by Mark in the comments:
import request from 'request';
import FormData from 'form-data';
export const handler = async (event, context) => {
// --- here, promises work with return values
return new Promise((resolve, reject) => {
// ... rest of your code
});
};
But can be simplified extensively (assuming modern Node.js) without any nesting:
import request from 'request';
import FormData from 'form-data';
import { promisify } from 'util';
export const handler = async (event, context) => {
const form = new FormData();
console.log('Streaming ...');
form.append('file', request('https://cdn.mysite.com/video.mp4'));
console.log('Uploading ...');
// Invocation ends here!
await promisify(cb => form.submit('https://www.someapi.com/upload', cb))()
const bodyParts = await response.toArray();
return response.map(x => x.toString()).join('');
};
In general you almost never need to wrap things in new Promise
in code.
CodePudding user response:
I was able to resolve this by using a non-async handler, and removing the promise from the code. Here's a working copy of my code:
import request from 'request';
import FormData from 'form-data';
export const handler = (event, context, callback) => {
const form = new FormData();
console.log('Streaming ...');
form.append('file', request('https://cdn.mysite.com/video.mp4'));
console.log('Uploading ...');
form.submit( 'https://www.someapi.com/upload', (error, response) => {
if (error) throw error;
let body = '';
response.on('data', chunk => {
body = chunk.toString();
});
response.on('end', () => {
console.log('Done ...');
callback(null, JSON.parse(body));
});
response.resume();
});
};
In this case, the Lambda function will wait for the callback
to terminate, based on the AWS Lambda function handler in Node.js documentation.
CodePudding user response:
I believe this has something to do with the default timeout value of Lambda.
By default, Lambda stops executing a function after 3 seconds.
If your code needs to run longer, you can modify the timeout settings in General Configuration of a specific Lambda function:
[ ] https://docs.aws.amazon.com/lambda/latest/dg/configuration-function-common.html#configuration-common-summary
The maximum timeout value is 15 minutes as of 15-09-2022.
I recommend you try increasing this value.
Hope this helps!!