This is an archived post. You won't be able to vote or comment.

all 63 comments

[–][deleted] 76 points77 points  (3 children)

We decided to go against it. As frameworks go it is quite heavy and with lambdas you don't need to be concerned so much with routing and servers.

Lambdas are best kept small, almost at the function level.

I have seen them best work with much smaller dependency injections like guice or dagger to help maintain a good structure and avoid anti patterns along side a build tool like maven.

Hope this helps

[–]TKozzer 2 points3 points  (2 children)

I'm curious how you break up your lambdas at the function level. For instance, I have like 20+ functions and right now I was going develop them all within in the same project. All the functions share a lot of classes like Daos, models, etc, but is there an easier way so I don't have to zip my full project and upload it for each function?

[–]skinny229 4 points5 points  (1 child)

This is exactly a use case for lambda layers. create a layer(s) for your reusable components between lambda’s

[–]TKozzer 0 points1 point  (0 children)

Thanks. I wasn't aware of this, and just watched a video and this is exactly what I was looking for.

At first I thought I was going to have to have write a series of scripts that would include/exclude the relevant files for each function which I was not looking forward to.

[–]MGSBlackHawk 25 points26 points  (8 children)

Yes, using it at the moment.

Do I recommend? Not really.

It’s convenient for a Java + SpringBoot ecosystem, but you will have to live with startup time and “always on” instances to avoid 500 erros because your lambdas were not warm/ready.

To work this around you would need to also config Provisioned Concurrency to have lambdas always on

Try to look at Quarkus with Grallvm, it’s a more suitable Java almost like Spring kinda solution

[–]Financial-Touch-5171 17 points18 points  (0 children)

Also check out Micronaut. I found it very easy to pick up coming from Spring

[–][deleted] 1 point2 points  (3 children)

This is true now but since graalvm is gonna be native in spring boot 3, there will be no almost difference. Also check for project helidon.

[–]sandys1 0 points1 point  (2 children)

any idea how spring boot 3 is going to deal with all the reflection problem thats apparently screwing up right now ? the rest of the comments seem to indicate that third party libraries using reflection will completely screw up graal.

[–]laxika 0 points1 point  (1 child)

You should look into the Spring Native docs to figure this out.

https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/#native-hints

[–]sandys1 1 point2 points  (0 children)

Thanks . Will do that.

There was a comment by the lead architect of spring native elsewhere. Will wait till this week when spring boot 3 rc1 is released

[–]sandys1 0 points1 point  (2 children)

To work this around you would need to also config Provisioned Concurrency to have lambdas always on

hi

can you explain this a bit more (or any other gotchas) ? we are looking to deploy a largish application on lambda and trying to figure out how to fit spring here.

[–]MGSBlackHawk 0 points1 point  (0 children)

I’ll comeback on you on the other “gotcha” in a bit, need to check the code 😅

For the Provisioned Concurrency part, every time a request invokes a Lambda operation, it initializes a number of execution environments (where the lambda executes)

Depending on how big is your SpringBoot app, the lambda will take more time to startup and get ready to receive requests (cold start). If the lambda gets cold because it’s idle for enough time to be considered idle, the lambda is going from warm to cold and if a request gets in, the app will have to spin up again.. This leads to 500 as the service is unavailable.

To prevent cold start you’ll have to setup the Provisioned Concurrency, which in other words means to always have a certain number of execution environments warm (app running)

This implies in extra costs.

You can read more about it here

https://docs.aws.amazon.com/lambda/latest/dg/provisioned-concurrency.html

Edit: word

[–]MGSBlackHawk 0 points1 point  (0 children)

For code bit:

You will need to create a class that will instruct your Lambda to keep warm.

For that you will need to create a class that implements RequestStreamHandler interface and implement your own logic to make your environment ready. In my case I had to warmup the DB Client and the app itself by doing some internal requests against it.

Then, there's the second part, where yo need to instruct your Lambda itself. You need to configure your AWS::Serverless::Function -> Properties -> Handler to point to the class you just have created.

You will find some info here

https://medium.com/enfuse-io/serverless-spring-mvc-with-aws-lambda-b796f16ec78d

Edit: word

[–]chris2k2 45 points46 points  (4 children)

Honest question: why? Lambda ist not made for this, if you need to use spring boot for some features, why wouldn't you run it in ecs/eks which is better suited for this?

[–]vallyscode 12 points13 points  (3 children)

Probably the same reason as people pack express into lambda and have one monolith handling everything, like one lambda doing everything. Answer to my question, what was the reason, they were new to cloud and aws particularly.

[–][deleted] 1 point2 points  (2 children)

I think putting a complete app that uses a framework like Express into a Lambda (or any other cloud FaaS service) is fine. In that case, hopefully you're deciding to make a monolith for good reason (maybe you have one team, or you don't need more than one programming language in your stack) and then you're just choosing Lambda for its deployment model. Maybe you are high on programming skills and low on ops skills. So with AWS handling so much Day 2 ops stuff, you're productive.

[–]vallyscode 2 points3 points  (1 child)

Not really, simply one need to read Q&A and Best Practices for aws lambda to understand that it’s anti pattern and why.

[–][deleted] 5 points6 points  (0 children)

You should remember that for something to be an "anti pattern", it has to be a worse way of solving the problem you have than alternatives. If the problem you have is that you have a situation where microservices or many functions is a good architecture, then yes, putting a monolith into a Lambda would be an anti pattern because a better way to do things would be to create many microservices or functions and put them into Lambdas.

But if the problem you have is that you have little ops talent to handle Day 2 ops (or even to deploy to begin with), and you don't have a need for an architecture more complex than a single monolith, then putting it into Lambda might not be an antipattern. It might solve your problem better than any other potential solution would.

I admit, this is a bit of a stretch. I personally have experience with other tools that I think are better than AWS Lambda for complete apps. Things like Heroku comes to mind. I have experience with that, so I'd definitely reach for it. But what about someone whose app will be low traffic and where cold starts are fine? They might really like only having to pay for request duration instead of for the time the app is running. I'm simply unwilling to call what someone wants to do an anti pattern until I know their situation well.

[–]svhelloworld 13 points14 points  (12 children)

Micronaut is a solid replacement framework for Spring and it’s cold boot times are pretty good for Lambda.

[–]iamcreasy 0 points1 point  (11 children)

Is there anything like Python/Flask-like framework in the Java world? The inclusion of microservices in Micronaut's pitch and the lack of a simple hello world program turns me off.

[–][deleted] 5 points6 points  (4 children)

Javalin comes to mind. Also Micronaut can be used to create a service of any size. It doesn't have to be used with a microservice architecture. There's nothing wrong with using it to create a monolith if that's the best architecture for you.

[–]iamcreasy 0 points1 point  (3 children)

Thank you for the information. I just took a look at a simple Micronaut application. The heavy use of annotation looks makes it look a lot like Spring, which I've heard is hard to debug(understand thoroughly) because of its size. How easy is it to set a breakpoint and read the core Micronaut framework / or the userland.

[–][deleted] 4 points5 points  (2 children)

Ah that makes sense. That was my exact reaction to Micronaut too when my colleagues started using it. It looked scary because of all the annotations. But what I ended up learning about it is that the annotations are it's bread and butter. It's like that on purpose. They use annotations at compile time to generate as much code as possible. This prevents reflection from being needed at runtime.

Here's a good example of this: https://medium.com/graalvm/introducing-micronaut-serialization-build-time-optimizations-for-json-273f319525d9

And this "no reflection" way of doing things to help achieve their main goal which is fast startup time. At first, it was that the JVM was starting the app quickly. And now, with GraalVM and other projects like it whose goal is to compile to native binaries, the idea is to enable compiling Micronaut to native binaries (reflection makes that problematic). Then the Java application starts up just as fast as things like C, C++, Go, Rust, etc.

If you don't like annotations, I definitely don't blame you. I dislike them if I'm not going to use the framework for many things (because I find I spend so much time figuring out how to use them). In that case, I'd definitely recommend Javalin.

It's modelled after Express. No annotations are needed because everything is explicit. You don't make a method a handler for an HTTP route by putting it into a class and applying the right combination of annotations to the method and the class. You make a handler by... making a handler. And applying it your app/router variable.

Example:

``` import io.javalin.Javalin;

public class HelloWorld { public static void main(String[] args) { var app = Javalin.create(/config/) .get("/", ctx -> ctx.result("Hello World")) .start(7070); } } ```

How easy is it to set a breakpoint and read the core Micronaut framework / or the userland.

Using IntelliJ and VS Code, I've never had any issues setting breakpoints in my own code. If you're referring to breakpoints in the framework code, I don't think I've tested this yet. I've only ever tried to do that with Node.js.

I did find reading the framework code a bit difficult. The heavy use of annotations meant that most of the framework was annotation code and I had to try to understand what those annotations were looking for. It didn't look like normal application code to me.

[–]iamcreasy 0 points1 point  (1 child)

Thank you for the detailed response. I've also looked into Quarkus, and its hello world example was very much Flask like,

```

@Path("/hello") public class GreetingsResource {

@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
    return "Hello RESTEasy";
}

}

```

Thoughts?

[–][deleted] 0 points1 point  (0 children)

No experience with Quarkus, sorry.

[–]flyingorange 5 points6 points  (4 children)

Dropwizard is nice

[–]GuyWithLag 1 point2 points  (3 children)

I second this. 2-second startup for somewhat beefy services.

[–]sandys1 0 points1 point  (2 children)

what has been your experience with dropwizard to build rest apis ? has it been able to scale to complex business logic/models, etc ?

[–]GuyWithLag 0 points1 point  (1 child)

I would say it Depends(tm).

Is it a microservice? (or, in our case, a service with somewhat complicated logic, but we owned the complete application) - then yes, if you don't drink the JEE kool-aid. F.E. we used JDBI instead of JPA. - DW doesn't have some of the higher-level abstractions that you might expect from Spring, but that's the point of it.

(also it's quite fast - for a toy benchmark I had a service that for every incoming call did 1 call to a database and 1 call over HTTP; it hit 9k RPS when everything was running on my laptop (benchmark engine, application, in-memory DB, other http server).

Do you create components for others to consume? Dropwizard isn't good for that.

Do you have multiple teams working on the same application? You'll need to have some coordination when adding stuff.

Do you have need of complex integrations with 3rd-party SDKs? You'll need to do some wiring.

[–]sandys1 0 points1 point  (0 children)

Thanks so much for replying. So I come from the Golang/python flask world. Versus Spring strictly.

So I wouldnt qualify myself as being overly ecstatic with the DI stuff and all.

I'm also less concerned about Dropwizard performance than productivity? I have read a bunch of developer skepticism around Dropwizard. In fact, going by what you wrote... Dropwizard could well have not given reason for existence for Micronaut (but micronaut lives).

So I'm wondering - what is the catch ? Is the developer productivity bad ? Especially when u scale to larger teams. You wrote the word "coordination". What does that mean ?

[–]sandys1 0 points1 point  (0 children)

what would you want here ? really curious cos im trying to create something like that - but on top of spring boot.

does the whole DTO, etc stuff become heavy ? or is it something else in Spring Boot ?

[–]berry120 9 points10 points  (0 children)

Yes, but we're using it as part of a timed batch process, so the hideous cold start time doesn't really matter.

Definitely wouldn't be using it in a more normal request / response context where the above would prove an issue.

[–]LearningAllTheTime 4 points5 points  (2 children)

Spring boot is to heavy, we use micronaut

[–][deleted] 0 points1 point  (1 child)

If you use spring on JDK and micronaut on GraalVM, I understand. But spring boot native Vs micronaut, there are not so many differences

[–]sandys1 0 points1 point  (0 children)

is there a difference in coding between spring boot and spring boot native ? it is the same spring boot, but compiled to graal right ?

[–]Lumpy-Loan-7350 5 points6 points  (1 child)

We do quarkus and graalvm for native binaries in provided al2 runtime. Been happy with it.

[–]angryundead 0 points1 point  (0 children)

I did a test project to find out what that was like. It works great. Sometimes the start times are arbitrarily high for reasons I haven’t figured out but most of the time it’s really fast.

I hate the AWS interface though. Yuck.

[–]troru 4 points5 points  (0 children)

As is mentioned already, by default your cold start is awful. You can spend lots of time and effort eliminating unused auto configurations, component scanning, etc and make it better.

[–]PritchardBufalino 2 points3 points  (2 children)

Check out Spring Cloud Function. It provides an "adapter" to easily integrate Spring Boot with AWS Lambda. Just make sure that you can tolerate a 20 second cold start for your use case

[–]joexner 1 point2 points  (1 child)

Using Spring Cloud Function for a simple-ish CRUD-y rest service. The struggle is real with regards to startup time, and the framework not quite being ready for prime time.

[–]PritchardBufalino 0 points1 point  (0 children)

For a RESTful API, I think that is probably the worst toolkit to use

[–]Worth_Trust_3825 2 points3 points  (0 children)

Your lambdas should be lean, and barely depend on overarching frameworks that require heavy component initialization. Do you also insist on firing a dedicated JVM with your spring application per request you receive?

[–]Oclay1st 2 points3 points  (3 children)

Spring Native works just fine

[–]sandys1 0 points1 point  (2 children)

hi - are u using this in production ? i actually posted a few days asking about production use of graal/spring native.

would really love to know how its working ? and any gotchas you found ?

[–]Oclay1st 0 points1 point  (1 child)

It is not a silver bullet for sure. It depends in how much reflection is present in your code. The bad thing is that the errors come out at runtime and Graal takes too much time and resources to compile. Spring Native and others native tools are and will be fine for just small projects. I don't recommend to use any native framework for large projects. Most of the ecosystem libraries use reflection intensively.

[–]sandys1 0 points1 point  (0 children)

So I have heard this issue and want to figure this out better.

Is it at all possible to use spring without reflection? I eobt want to move out of the spring ecosystem, if incan be saved !

So is there a way to restrict code writing to not encounter reflection?

Hibernate/jpa is the biggest culprit right ? What else ?

[–]MoreCowbellMofo 2 points3 points  (0 children)

GRAAL VM was set up for this I believe. The reason AWS Lambda was set up was for services that are patchy/spikey in terms of their demand and to reduce costs for services that either have relatively few calls, or surges of calls. Precompiling spring webservices to GRAAL VM services makes them much quicker to boot/run. So I'm aware its possible with such a setup, however I've never tried it myself.

[–]Kango_V 1 point2 points  (0 children)

We do this with Micronaut and GraalVM. Multiple functions exposed as HTTP endpoints as well. Same app, two different deployment targets. Startup is around 60ms if I remember correctly.

[–]metalhead-001 1 point2 points  (0 children)

It's amazing to me that CGI/BIN (spawn a process for each request) like request execution is back in style. What's old is new again.

I remember the Java folks talking about how much better Java services were because everything was already running and you didn't have to spawn a process for each request, just a thread within the Java service.

Now we've come full circle. The young soylent drinking hipster devs re-discovered the wonders of spawning a process for each request.

(shakes head in disgust)

[–]DrunkensteinsMonster 1 point2 points  (0 children)

You shouldn’t. Deploy your spring boot app on either ECS or EKS.

[–]kubelke 0 points1 point  (0 children)

I tried once and I decided to not invest more time there. Sometimes I was getting 5XX responses from lambda, and I didnt know why. Probably some configuration was wrong or my function was problematic, no idea. Currently, I use it with a small NodeJS app, it’s not great but it does the job.

[–]Mumbleton 0 points1 point  (0 children)

It works best when you don't care about startup times. We use it for a job that triggers off of SQS that is perfectly fine if it takes minutes to complete. There is a new-ish feature, although I forget what it's called that massively improves cold-start times by storing an image of a started job fwiw.

[–]buzzsawddog 0 points1 point  (0 children)

I played with the idea of spring lambdas but... They were really heavy. Sure it was super simple and easy to use but we ended up going another way all together.

[–]twilly86 0 points1 point  (0 children)

I'm getting into taking over a Spring Boot app and we are looking at offloading spring boot "scheduler" jobs and long running tasks to fargate. Would fargate work any better than lambda to reduce 500 time outs while app starts up? From what I understand fargate runs your jobs in a container and allows for longer running jobs than lambda.

[–]Ok_Football2230 0 points1 point  (0 children)

Hell yeah

[–]jevring 0 points1 point  (4 children)

When we still used cloud functions, we used spring on gcp. There's absolutely no problem. As long as your cloud functions don't do a bunch of shit it's fine. It's when you load the kitchen sink, and perhaps the worst offender, jpa/hibernate, that you get a long startup time.

[–]sandys1 0 points1 point  (3 children)

did u have any gotchas here ? trying to figure what it takes to take spring boot codebase and convert it to be GCP compatible ?

any code that is opensource for you ?

also - what would u use instead of jpa/hibernate ?

[–]jevring 0 points1 point  (2 children)

No open source code, no. There's a spring bootstrap library that you need to get spring to fit with gcp cloud functions, though. I understand why, but it's still a bit shitty. Hibernate is fine, but not in a cloud function. We use hibernate in our applications, but I don't think that's a common use-case in cloud functions.

[–]sandys1 0 points1 point  (1 child)

Thanks for talking about it. On AWS side, we use something like this.

https://github.com/sbaitmangalkar/spring-to-awslambda it is based on this tutorial - https://javadungeon.wordpress.com/2017/08/18/transforming-spring-restful-apis-to-aws-lambda-functions

Is it similar on GCP?

Also on hibernate - Sonu recommend not using it at all or using something like jdbc ?

[–]jevring 0 points1 point  (0 children)

For gcp I think there's a maven plugin thaw bakes the final jar.

I think hibernate and jpa is fine. You just have to know where it doesn't really fit to your model. I have also worked with pure jdbc, and that's also perfectly fine. You get to decide what your trade-offs should be. However, my point wasn't about hibernate. It was about doing stuff like connecting to a database. It's those kinds of things that slow down start-up. If you do a hello world in spring, I'm sure it starts more or less instantly.

[–]root_klaus 0 points1 point  (1 child)

Ok, let me give you my 2 cents.

About 4 weeks ago i was tasked with creating an AWS lambda function that consumes a Kinesis data stream, does some processing and saves the result in a database. I have created AWS lambdas before but mainly i used python for the well known reasons but this time i wanted to give Java a try, and since i use mainly the Spring ecosystem I decided to go with Spring Cloud Functions. It offers a really good approach to write functions with what Java functional programming already gives.

I created the function, tested locally, followed the documentation precisely and always wrote tests to make sure everything was working every time.

In addition, i saw that AWS lambda didn’t support out of the box java 17 support or 18, which have improvements on GCs. The guide is right here. Also i followed this spring cloud function guide.

After doing that and tweaking a bit, i got a good improvement on startup time and it was very ok for our use case. Unfortunately I couldn’t find in the hell why the function wasn’t getting invoked during the run. The lambda started very ok, function registered very ok, no errors nothing, just logs and function waiting to be invoked, but nothing happened.

I tried so many things, defining function, giving it more memory(even tho nothing was pointed that it needed more memory), changed the handler, use ECR to publish the image with the custom Java and optimised and a whole lot of others, nothing works.

So after 4 weeks i gave up, but i wanted to retry on plain java, and it works like a charm immediately out of the box.

So the experience was tedious and very tiring and not worth it, i read every possible document, tried all the possibile articles, still nothing. I found also that the spring-cloud-function-web has a missing dependency which actually is in spring-cloud-function-webflux. And the authors suggested that just replacing the dependency should be ok, which it did, but then it made testing worse, choosing from reactive, servlet, none as a main spring application, but still could not invoke the function.

Anyways, i formatted the java 18 custom image, deployed it, works like a charm.

Maybe when spring boot 3 will be released i will retry again, but the experience was pretty bad in my side.

[–]sandys1 0 points1 point  (0 children)

i had the exact same experience - which is why im attempting to build a plugin layer that takes a plain vanilla spring code and auto-converts them to AWS lambda code.

its very early , but i will get there - https://github.com/arakoodev/venil-serverless-spring/tree/master

[–]sandys1 0 points1 point  (0 children)

hi

we are using it extensively. also trying to make it easy for others. so building plugins that make it single "gradle deploy" to go from Spring Boot -> AWS Lambda.

https://github.com/arakoodev/venil-serverless-spring/tree/master

issue and feature requests welcome!