-
Notifications
You must be signed in to change notification settings - Fork 353
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
Fix sam local support for missing headers (#38) #332
Fix sam local support for missing headers (#38) #332
Conversation
* Added unit tests for TryFrom<HeaderMap> for Context
.to_str() | ||
.expect("Missing Request ID") | ||
request_id: headers | ||
.get("lambda-runtime-aws-request-id") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of implicitly failing (by panic-ing on a missing key), i retain the original panic behavior, but now we panic at the expect
as expected :) -- I think in the original code we don't ever make it to the expect
because it panics on the attempt to dereference headers["lambda-runtime-aws-request-id"]
. However, I kept the panic language to refer to "lambda-runtime-aws-request-id", because I found the specificity was very helpful in tracking down the bug.
I chose not to change the panic to an Error here, since sam local does fulfill this requirement, so no need to be prematurely lax.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, thanks for fixing this.
.to_owned(), | ||
deadline: headers["lambda-runtime-deadline-ms"] | ||
deadline: headers | ||
.get("lambda-runtime-deadline-ms") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
took same approach as "lambda-runtime-aws-request-id" here.
invoked_function_arn: headers | ||
.get("lambda-runtime-invoked-function-arn") | ||
.unwrap_or(&HeaderValue::from_static( | ||
"No header lambda-runtime-invoked-function-arn found.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of honoring ARN format, I only honored the "String" type of ARN. In production, of course, it should be a real ARN. But in development (such as sam local), it should be clear that something is wrong with the environment, if the developer somehow needs to inspect this context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. One of my original worries was if someone was using the ARN in some way it would be annoying to debug if the default looked like a real value.
.expect("Invalid XRayTraceID sent by Lambda; this is a bug") | ||
xray_trace_id: headers | ||
.get("lambda-runtime-trace-id") | ||
.unwrap_or(&HeaderValue::from_static("No header lambda-runtime-trace-id found.")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As reported in other issues, as well as confirming this myself, sam local invoke
also leaves off this header.
.to_owned(), | ||
..Default::default() | ||
}; | ||
Ok(ctx) | ||
} | ||
} | ||
|
||
#[cfg(test)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't sure exactly where to put these tests, so I just placed them right after the thing they are testing.
I noticed the other test in this file does not use #[cfg(test)]... I wasn't sure if I should have left it off here or not. As I understand, without adding #[cfg(test)], it would artificially bloat the release build as well. As I said, I'm still new enough to rust though, so please let me know if I misunderstand!
hum. so, i just noticed this: I'm curious if the position has changed at all. Given that other runtimes seem fine with these missing headers in the context of sam local, I'm wondering why the rust runtime would be different. I realize this might be something to revisit, if that context header becomes an invariant for later runtime machinery; but doesn't this bug make it even less likely that this runtime will rely an that header given the slower feedback cycle for development on it? Wondering why the strict abstraction barrier for those 2 specific headers at this low level. For the context of the the runtime consumer, that is, the lambda application developer, the devx of lambda without sam local is a big gap. I realized that while I was writing this template for myself: https://github.com/kenshih/rust-aws-lambda-template. I was reluctant to share it with anyone on my team without a good lightweight solution for local development. |
Ok. So feel free to close this, as you like. I'm seeing the arguments more clearly: #314 I'll leave this open until you get a chance to see it, just as another +1 to the situation this runtime is left in & the pain it causes. Thanks for your work. |
Revisiting what i did here, I now think neither approach (this PR, as well, not doing this PR) is good. Following the Robustness Principle... I wonder if the runtime instead should:
The cost, of course, is a more complicated interface with the consumer (Option vs. guaranteed data). But, at the same time, good side effects are: it would encourage promulgation of the robustness principle down to the consumer & reflects the reality of the often imperfect situation inherent in layer & cross-subsystem dependencies. Contracts break. So do we live with months/if-ever delays in the meantime, or robust our way out of it, knowing we're exposed to some interface risk? I honestly don't know the right answer here. But curious to hear the balance the maintainers of this runtime hope to achieve. Thanks for listening. |
FWIW as a user of this project, I don't care at all about the lambda context, and I do wish we could run with sam local. Option values in Context isn't the worst idea in the world. |
Yes please, un-draft this PR and get it shipped, it'll help a ton to have a proper |
So I'll be happy to un-Draft this, @brainstorm, thank you. But I need a Maintainer to allow me to merge, or at least comment about how I can move this into a solution that would be acceptable. Would moving Context values to Option values and emitting WARN be an acceptable compromise, @maintainers? In the interface code, I would link a comment to the doc of the contract interface and explain the robustness approach we're taking. Meaning, we can make the framework (in this case, the lambda runtime) more resilient than the contract it accepts data from via such defensive coding. While this may seem like a technique we don't need as much of in Rust, certainly the world outside of Rust does not abide by Rust assumptions, so at the edges, we still use resilient/robust techniques instead of falling back to fragility. I think of it this way, if I'm an engineer/architect that wants to push my team to the latest platform, but I see it has a bug in headers it passes, I'm blocked on AWS fixing it before I can take advantage of latest bug fixes/improvements, putting AWS' Rust ecosystem at a needless disadvantage vis-a-vis other runtimes. I realize assuming Context contract as golden means the runtime itself can make assumptions and more easily maintain future instrumentation, etc... but in that too, we should have graceful failure modes. So it might be a better assumption to data clean just inside the interface anyway. Curious to hear your thoughts, @maintainers, and if you buy what I'm saying here. |
Apologies for the radio silence, all. I've been on vacation a bit and also been very busy with another deliverable at work so I didn't have time to check everything out in detail. I've come back to looking at this now. In the past I took a hard stance against setting defaults like this for the reasons you mentioned above, but at this point it appears this won't ever be resolved unless the runtime is more graceful in handling these missing headers for local environments. At this point I'm inclined to think the way you've done this PR right now is fine. I like that you provided default strings that make it abundantly clear that something funky is going on if someone were to run into this in production. I think I'm inclined to keep it this way instead of making values in the Lambda context optional, as that isn't really reflective of reality when run outside of SAM. I'm curious to know what @bahildebrand thinks about this, but I think this PR is acceptable, personally. |
.to_str() | ||
.expect("Missing Request ID") | ||
request_id: headers | ||
.get("lambda-runtime-aws-request-id") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, thanks for fixing this.
invoked_function_arn: headers | ||
.get("lambda-runtime-invoked-function-arn") | ||
.unwrap_or(&HeaderValue::from_static( | ||
"No header lambda-runtime-invoked-function-arn found.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. One of my original worries was if someone was using the ARN in some way it would be annoying to debug if the default looked like a real value.
I'm going to go ahead and merge this, if there are any issues with this approach we can discuss. |
Thanks much for the contribution! @kenshih |
…rust-runtime#332, hopefully get rid of two flukes from the list
This works neatly! Could you produce a release? I'm pinning to a commit right now, but I reckon that a ton of users would benefit from this. |
@brainstorm Sure thing, I will work on getting 3.1 published today or tomorrow. |
@brainstorm Okay, all pushed. Apologies on the delay of a couple days! |
It works beautifully, thanks! |
Hello, I hope this finds you well!
I was trying to run
sam local
in order to make using rust more viable at work & got it working locally, so I thought I'd throw up a pull request, in case it solves an issue for other alpha runtime users.Fix sam local support for missing headers (#38)
Issue #38
also related to:
Example of problem:
After the following changes, the above stack trace was no more & the lambda invoke was able to run successfully to completion with expected response payload.
Description of changes:
Fix sam local support for missing headers (#38)
The issue was that when the lambda-runtime is invoked by the sam local simulated environment, the headers
lambda-runtime-invoked-function-arn
andlambda-runtime-trace-id
are not provided (as they are in the production cloud environment).I have confirmed this issue still exists in
v0.3.0
and onmaster
I'm not aware if these headers are supposed to be invariants or not, but, it seems that other language runtimes are more forgiving with these missing headers with
sam local invoke
, so it seems appropriate for the rust runtime to be resilient to these as well?Instead of panic-ing on a missing header key, this code now provides a default value for the two headers in question. The default string indicates that they were not found in the environment as expected.
Let me know if you the style is not to your liking, happy to change as you suggest and/or accept incoming changes. I am rather new to rust. Apologies if I have misinterpreted any conventions.
Thanks for considering this PR.
By submitting this pull request