Open naftulikay opened 6 years ago
Please be advised that Amazon has since added more metadata to their calls, so the difficulty here is that things will be masked by serde only deserializing the fields it knows about.
This is awesome! I was actually motivated enough to start a bridge project https://github.com/softprops/lando to add event types ( api gateway is all I needed ) . What is the likely hood we could iterate and cut releases quickly with this. I would love to just start using this today. That's a big list of checkboxes and I'd love to just get going with a release version.
Aside. I took a slightly different approach that users might appreciate. When deploying a lambdas its atypical for a single function to service multiple types of events. Rather is more common for a single lambda to target a single type of trigger.
A slightly different approach I was taking was to have a named macro per event type, in this case
gateway!(
|request, context| Ok(lando::Response::default())
);
So that a lambda targeting a certain trigger would only have to focus on a function types that are relevant vs having to on one extra level of pattern matching. I think something like that could be added in addition to this approach separately.
Either way this looks great and I don't want to duplicate effort. How likely would it be that we could break up this large list into smaller lists and release more often?
Yeah, let's break things into pieces. Packages should be nested as represented above.
FWIW my use case is a single Lambda function dispatching all the events.
I think thing the single lambda is a really good default. I'm excited to see where this goes!
I wasn't sure where the best place to post this would be this seemed reasonable. I just announced a crate release that builds on on crowbar that adds bindings for the standard http crate to crowbar https://twitter.com/softprops/status/1003458005852196870. I can likely simplify my implementation when some of these the changes in this issue get addressed.
My workflows for aws lambda mostly revolve around the serverless framework so I made a serverless plugin to help facilitate rustlang applications https://github.com/softprops/serverless-rust. This should also by extension work well with any crowbar application.
Ya'll may be interested in https://github.com/srijs/rust-aws-lambda/tree/master/aws_lambda_events. I generate the event structs from Go. I'm going to publish it as its own crate soon.
What's the status on this and how I help push it forward?
@softprops I think we need to consolidate around a singular place for these definitions and I'm not sure that this is the best repository for it, we should probably put it in rusoto
or something like that. FWIW here is some sampling of what I'm doing with my own Lambda API:
lambda!(|event, _context| {
INITIALIZE.call_once(|| {
logging::initialize();
threading::initialize();
debug!("Finished one-time initialization.");
});
if env::var("DEBUG").map(|s| s == "true").unwrap_or(false) {
// if we're in debug mode, dump
debug!("Event: {}", to_string_pretty(&event).unwrap());
}
// dispatch event based on its type
match serde_json::from_value::<Event>(event) {
Ok(Event::Auth(event)) => Ok(to_value(&service::auth::route(&event)).unwrap()),
Ok(Event::CloudWatch(event)) => Ok(service::cloudwatch::route(&event)),
Ok(Event::Http(event)) => Ok(to_value(&service::http::route(&event)).unwrap()),
Ok(Event::Records(records)) => Ok(service::multi::route_all(records.entries)),
Ok(Event::Unknown(event)) => Ok(service::unknown::route(&event)),
Err(_) => {
error!("Unable to convert event.");
Ok(json!({ "statusCode": 400 ,"message": "Unable to convert event." }))
}
}
});
Here's my Event
enum:
#[derive(Deserialize)]
#[serde(untagged)]
pub enum Event {
CloudWatch(cloudwatch::Event),
Auth(auth::Event),
Http(HttpEvent),
Records(Records),
Unknown(Value),
}
The ergonomics of Rust are amazing for this purpose. Static routing like this gives me 500 microsecond response times, which is almost unthinkably fast, Amazon bills by 100ms intervals, I'm 200x faster than that :100:
I'd love to see a hierarchy expressed like this, perhaps using the underlying data objects from rusoto
in enums for the Lambda entry point. It's really hard to get things working for Rust + Lambda (largely because the underlying Lambda system image is really old, no fault of crowbar
), but once it's working, it's a joy to use!
I'd love to see more forward progress on this, but I'm currently pretty busy and haven't been able to devote time to my API as much as I'd like.
Rusoto is a boto client for rust. Boto only describes aws services. If it also describes lambda event data models :thumbsup: if not I feel like a stand alone crate on its own release schedule would do. I'd go so far as to say especially for the release schedule. I think rusoto is a bit reserved in releasing often because it rereleases all of its crates in batches bumping versions when nothing's changed. For something like a crate of lambda event datastuctures I'd imagine the change cycle to release time to be super short.
Yup, we're on the same page! I thought that somebody had done it already, but I could be mistaken. If anyone wants to start that, please do and I'll contribute some work at it.
I did: https://github.com/srijs/rust-aws-lambda/tree/master/aws_lambda_events. It doesn't have any deps on a particular rust framework and is auto-generated from the official go typedefs. It even autogenerates tests and uses the example json from the official go lib.
The generator is https://github.com/srijs/rust-aws-lambda/tree/master/aws_lambda_events_codegen.
That being said, all those cloudwatch events are out of scope....I'm only focusing on Lambda events.
@naftulikay would you be open to publishing what you have now in a stand alone crate. I'm using crowbar at work in a growing number of places. I would use said crate as soon as you'd publish it :)
@LegNeato ha I started typing before you posted. Would you be able to put that in a repo and on its own release schedule? I fine is convenient for maintainers but less so for users to have projects that release multiple artifacts because of the release coordination involved ( publishing new versions of things when they haven't changed as an artifact :) ). It also makes it less daunting for outside contributors. If you published that today I'd use it.. tomorrow :)
Knowing this exists it'd be great to consolidate efforts. A separate create would keep crowbar super small for cases when you may not gain much from the structures, scheduled crons ECT.
@LegNeato this looks great! I could shed some fur I've grown in another crate with your data structs
https://github.com/softprops/lando/blob/master/src/request.rs
What dependencies does your data structures crate have on its parent project?
@softprops Zero deps on the parent project. The parent project consumes it and reexports. I was doing my own runtime with gob encoding and decided to join forces. It also helps to have a project that is testing it while developing, hence why it is part of the workspace. It was always envisioned as a crate that can be used with all rust lambda runtimes even though it lives in a specific one's repo...which is why I posted https://github.com/ilianaw/rust-crowbar/issues/32#issuecomment-394627582 😄
I added a README and do intend to publish it soon. I wanted to get https://github.com/srijs/rust-aws-lambda/issues/8 in first though.
@LegNeato sounds great! Having it embedded in another crate without actually depending on that the other crates makes it harder to discover and potentially more tricky with ci since itd be coupled to its parent projects ci. I'm not sure if how much value you're getting from the embedding now but I assume it would actually make it easier to manage independently from a contributor/ci/release cycle stand point in its own repo. Either way I look forward to its release!
https://github.com/srijs/rust-aws-lambda/issues/8 is an great example. It seems this would be easier to manage changes specific to the data structures in its own crate which you can manage/release independently
I will shortly post my data types that I have internally defined. Unfortunately they're in a non-public repository that I don't plan on making public.
Here it is everybody, I apologize it's in a Gist, but it's what I can ship for now: https://gist.github.com/naftulikay/99f4ab201c7efddb2210930f411e60e4
I have a series of test cases which should make things clear. Basically mod.rs/Event
is the root value that the Lambda function will receive. It disambiguates into HTTP events (from API Gateway), CloudWatch events directly, API Gateway Authorization Events, or to a series of mod.rs/Records
which are mod.rs/Record
objects.
Records can be S3, SES, SNS, and other types that I haven't implemented yet.
Some of the more complicated flows are found in SES, where it's necessary to define types for full messages (basically SES -> SNS -> Lambda is required to get a full message) versus a "filter" action which allows bouncing emails, but only gives you access to basic metadata about the message.
I have unit tests stashed away and I have the Terraform required to create all of this, but it is likewise not open source.
@softprops FWIW I published an initial version of the events package: https://crates.io/crates/aws_lambda_events
@LegNeato that's great news!
TODO
JFC CloudWatch :skull:
Pull #31 is going to get some of this.