-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unable to run the lambda asynchronously #78
Comments
Please help me to resolve this issue. I confirm that while invoking the lambda running the GitHub app code, it works as expected |
the probot function code has to resolve before any webhooks can be received, but with your implementation it can only resolve after it received the first event, so you are in a deadlock, it won't work like this. Try this instead module.exports = async (app) => {
// Your code here
app.log.info("Yay, the app was loaded!");
app.log.info("waiting for event....");
app.on("issues.opened", async (context) => {
const issueComment = context.issue({
body: "Thanks for opening this issue!",
});
return context.octokit.issues.createComment(issueComment);
});
app.on("deployment_status.created", async (context) => {
let deployment_status = context.payload.deployment_status.state;
app.log.info(`deployment_status created: ${deployment_status}`);
const config = await context.config("config.yaml");
if (deployment_status == "success") {
app.log.info(context.repo().repo);
app.log.info(
`Deployment - exclude environement ${config.deployment.environment.excludes}`
);
app.log.info(sign(context.payload, "development"));
}
});
app.log.info("Exiting ....");
}; |
@gr2m Thank you so much for your prompt response. I tried the above code as you mentioned. Unfortunately, while invoking the lambda asynchronously, it's not waiting for any webhook request. Below is my lambda handler written using the aws-lambda-serverless adapter
|
That's as it should be, it's all good. You can remove this line
It gets executed before any of the webhooks handlers is. |
I'm not a lambda expert, I'm out of my depth here I'm afraid. We have an example app that is using this adapter and it worked: Maybe there is some clue in there that might help? I hope you can figure it out, please let us know when you do
|
Thank you so much for your response. I am a little confused why the lambda function is not waiting for the probot app to load. https://github.com/probot/adapter-aws-lambda-serverless/blob/master/index.js#L14 . Could you please let me know is there anything I am missing out here?
|
I figured out that the issue was with this line
By default, this value is true and callback will wait until the Node.js runtime event loop is empty before freezing the process and returning the results to the caller. By setting it to false, it's request AWS Lambda to freeze the process soon after the callback is called, even if there are events in the event loop. AWS Lambda will freeze the process, any state data and the events in the Node.js event loop. |
That's what we are setting here right? adapter-aws-lambda-serverless/lambda-function.js Lines 7 to 8 in 2b6a1f4
You are saying that setting it to false is causing problems for you? Shall we remove the line? I'm not exactly sure what the implications are, maybe we need to make it conditional? |
I am also not 100% sure about its implication. But, after changing the lambda handler to the below, it worked as expected.
So, maybe making it conditional would be the best. |
I had a similar issue, and this is how I resolved: module.exports.webhooks = createLambdaFunction(setUpFunction, {
probot: createProbot()
})
// your setup function should be like so - This is setUpFunction()
module.exports = (pbapp) => {
pbapp.log.info("Initializing Lambda");
pbapp.onError((error) => {
pbapp.log.error(error);
});
let lib = require("@lib/handle_some_event"); // I keep my code organized, or try to.
pbapp.on('some_event', lib.handle_some_event); //for exammple, deployment_status.created is an event
return pbapp;
};
// @lib/handle_some_event
//
exports.handle_some_event = (context) => {
context.log.info("handling some event");
//notice we are returning a promise
return new Promise((resolve, reject) => {
//DoSomeLongAsyncCallHere - note that this method also returns a promise.
//For example, this could be a function that drops a file on S3.
DoSomeLongAsyncCallHere().then((response) => {resolve(response)}).catch( (error) => {reject(error)});
});
}; |
I'm experiencing this issue as well. I've discovered a few things that I figured I would add to this conversation. First, here are some official AWS docs that talk about the purpose of
It seems like that option is only relevant to non-async functions (i.e. functions that use callbacks). Since the It seems like this issue only appears when using # this doesn't work
functions:
webhooks:
handler: handler.webhooks
events:
- http:
path: /api/github/webhooks
method: post
async: true
# this works
functions:
webhooks:
handler: handler.webhooks
events:
- http:
path: /api/github/webhooks
method: post
# async: true
# this works
functions:
webhooks:
handler: handler.webhooks
events:
- httpApi:
path: /api/github/webhooks
method: post
# async: true # this is commented out because the `httpApi` event does not support asynchronous invocations After going through the
So based on everything outlined above, I think it should be safe to remove
|
great research, thank you! I'm not using the adapter myself, so if you could send the PR I'm happy to merge, I'd just ask you to confirm that things are working as expected with the new version. If you could update any relevant docs as part of the PR that would be great |
No problem! I'm testing locally now. I will open a PR assuming everything works as expected. |
🙁 that actually didn't resolve the issue. I will continue investigating. I think it can still be removed regardless. |
Hmm. I can confirm that @SuchismitaGoswami's inlined excerpt above works correctly though. Here's mine, adapted for TypeScript. import { createProbot } from "@probot/adapter-aws-lambda-serverless";
import appFn from "./index";
import lowercaseKeys from "lowercase-keys";
let probot = createProbot();
probot.load(appFn);
export const webhooks = async (event, context) => {
try {
const headersLowerCase: any = lowercaseKeys(event.headers);
await probot.webhooks.verifyAndReceive({
id: headersLowerCase["x-github-delivery"],
name: headersLowerCase["x-github-event"],
signature:
headersLowerCase["x-hub-signature-256"] ||
headersLowerCase["x-hub-signature"],
payload: event.body,
});
return {
statusCode: 200,
body: '{"ok":true}',
};
} catch (error: any) {
return {
statusCode: error.status || 500,
error: "ooops",
};
}
}; I think this could imply that there's something wrong with index.js? Continuing my investigation. |
I'm stumped for now, but here's what I've found. With this functions:
handleProbot:
handler: dist/serverless.webhooks
events:
- http:
path: /api/github/webhooks
method: POST
async: true I can inline some of the import { createProbot } from "@probot/adapter-aws-lambda-serverless";
import appFn from "./index";
import lowercaseKeys from "lowercase-keys";
const lambdaFunction = async (probot, event, context) => {
try {
context.callbackWaitsForEmptyEventLoop = false;
const headersLowerCase: any = lowercaseKeys(event.headers);
await probot.webhooks.verifyAndReceive({
id: headersLowerCase["x-github-delivery"],
name: headersLowerCase["x-github-event"],
signature:
headersLowerCase["x-hub-signature-256"] ||
headersLowerCase["x-hub-signature"],
payload: event.body,
});
return {
statusCode: 200,
body: '{"ok":true}',
};
} catch (error: any) {
return {
statusCode: error.status || 500,
error: "ooops",
};
}
};
export const webhooks = (() => {
let probot = createProbot();
probot.load(appFn);
return lambdaFunction.bind(null, probot);
})(); But if I use the package functions from the import {
createLambdaFunction,
createProbot,
} from "@probot/adapter-aws-lambda-serverless";
import app from "./index";
export const webhooks = createLambdaFunction(app, {
probot: createProbot(),
}); Not really sure what to make of this, but I will pick this back up tomorrow. I really need the |
@SuchismitaGoswami, can you try re-running this code block with |
Fixes probot#78. This PR removes the `JSON.parse` call from `event.body`. This was causing issues when trying to invoke Lambda functions asynchronously with `async` set to `true` in a `serverless.yaml` config file. I'm not exactly sure why this doesn't cause issues when `async` is not set to `true`, but I tested these changes with `http` events (both `async: true` and `async: false`) and `httpApi` events and it seemed to work fine on both. Also, I believe the `verifyAndReceive` function internally handles both objects and strings anyway.
`callbackWaitsForEmptyEventLoop` is only needed for non-async functions (i.e. functions that use callbacks) and therefore can be safely removed from this package. See probot#78 (comment) for more details
Fixed it! This one was a challenge since errors aren't propagated when |
@ajschmidt8 Sure, I will give it a try and do the sanity check. I am a little busy this week due to personal reason. I will get back to this thread with my findings. But, great work on finding out the reason behind it. TBH, I hardly thought the issue could be due to JSON.parse when I raised this. I intentionally removed it from my code as, in my case, the |
`callbackWaitsForEmptyEventLoop` is only needed for non-async functions (i.e. functions that use callbacks) and therefore can be safely removed from this package. See #78 (comment) for more details
🎉 This issue has been resolved in version 3.0.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
I am having the app.js code like below. While invoking the lambda asynchronously, it's not waiting for any event emitter callback to execute.
The text was updated successfully, but these errors were encountered: