We figured out how to get Azure Functions to serve a complete webapp without any extra crap wrapped around it. No gateways/proxies/etc. One function that serves the root URL[0] and has conditionals for GET/POST methods. Beyond this point, anyone with old-school mastery of HTML/CSS/JS can get the rest of the job done with basic-ass SSR and multipart form posts.
For data, we just use Azure SQL Server. Authentication is like sticking legos together now. 100% managed identities, no magic strings, etc. Our functions get the user's claims principal right in the arg list. We have zero lines of authentication code in our latest products.
This stuff is absolutely the future for a vast majority of boring old business.
One thing to think about: If your FaaS offering is capable of serving content-type of application/json, is it not also capable of serving content-type of text/html? Do your providers go out of their way to prevent you from making a simple solve on 99% of B2B bullshit?
[0]: Note that serving the root URL on an Azure Function is an undocumented hack-around item. Worst case, we would serve the /app route and our users (B2B) wouldn't really care. My suspicion is that Microsoft detected our use case and saw that it stole a LOT of thunder from a wide array of other Azure offerings (API Gateway, Front Door, et. al.), so making it slightly more complicated (at first glance) is likely intentional.
Sounds like a cool hack, but why not just self-host with on-premises hardware, or rent a cloud server from a hosting provider like e.g. Digitalocean? Then you wouldn't have to worry so much about what Microsoft wants, no?
Who monitors it 24/7 and checks the alerts? Who drives to the data center to fix broken hardware on Christmas Day? It has to be multiple "whos" or one sick leave will leave you completely vulnerable.
For small-medium companies whose main business isn't hosting software this makes it untenable from a financial point of view. For the monthly salary of a single SRE/devops/admin whatever you can run AWS services for a year at that scale.
PII is a monster. We'd prefer our customers take charge of that. The goldilocks is running our stack on a tenant our customers are owners of. This way, everything is 100% consistent across the board and liability is on them.
We've got some experience with on-prem IT shops that have taken way more out of us than we probably should have allowed. Every one of their issues with getting our software to run in prod was unhappy in its own special way.
Why would you ever do this instead of just storing your static assets in the Azure equivalent of S3 and let it do the heavy lifting along with the CDN?
We are B2B at the scale of 1-10k users. There is no "heavy lifting" to do in our contexts of use. Serving static assets along with the SSR content is totally acceptable. They aren't even served as separate files. We inline everything into 1 final HTML payload always.
Our largest assets are SVG logos that our clients bring to the party. We do work with dynamic PDF documents, but these are uncachable for a number of reasons.
Hypothetically, if we had millions of users and static asset IO was actually causing trouble, we'd consider using a CDN or other relevant technology.
I bet you were running c#. Been pulling my hair out with the python support in Azure Functions lately (starts with no local emulation on mac, but positively this got me to start using VS code server and https://github.com/coder/coder ) .
We use Lambda monolith usually with a Lambda containing an entire REST JSON API node.js server.
It works very well.
I feel one of the reason why Lambda did not gain fast market traction is because all the initial tutorials focused on having an endpoint for each lambda, which is actually a special optmization edge case that can come later.
Services like Vercel just wrap the Lambda and indeed deploy an entire server to the Lambda and gained a lot of users this way.
Lambda Monolith are good replacement to the old Heroky dynos.
Lambda monolith are super cheap for B2B SaaS startups with little traffic
>Lambda did not gain fast market traction is because...
I'll extend this to all three cloud services, and dispute the assertion. Developers are smart and figured out that these serverless platforms are great for APIs even if the initial tutorials didn't present that scenario. Also, the platforms just got better at this over time while those early tutorials were somewhat cast in stone. I've not looked lately, but I would hope that they now have tutorials that show monolith scenarios.
>Lambda monolith are super cheap for B2B SaaS startups
Again, I'll extend this to Azure Functions and Cloud Run. Truly an amazing place we now sit. My first public facing API required me to build a physical machine and place it in a colo facility in town. Now I just run a command-line or check in my code and my API is live.
> I feel one of the reason why Lambda did not gain fast market traction is because all the initial tutorials focused on having an endpoint for each lambda
A big reason is that lambdas were half-baked and gradually became better. They are still limited.
Sending a binary blob? You have to convert it to base64.
Streaming a response? You can only do that on the nodejs runtime.
Establishing a short-term ws connection? Hard/impossible.
AWS limits are there to be worked around! Have too many lambdas to fit them in a single cloudformation stack? Just split it up into ‘per family’ stacks. Enjoy your nested cloudformation stacks.
Oh, you say you have more than 200 endpoints in your REST API gateway, and suddenly your CloudFormation stop working? Yes, unfortunately CF only load 8 pages of resources in alphabetical order when starting, and your root resource starts with a ‘Y’.
No problem, implement a new custom resource that just creates and discards API gateways until you have one with your desired root resource starting with ‘A-F’. Did I mention the ‘delete a rest api’ API is limited to a single call per minute? The fun doesn’t end. Now you may be able to grow until 600 resources before you’ll have to tighten the limits once again.
You say you think this is bollocks? Of course, just switch to an Application Load Balancer. Just 100 rules max means you’ll only need to nest about 4 of them to fit all your API endpoints.
And people wonder why some give up on the cloud. Any $5 VPS has higher limits than any of these AWS services…
I _just recently_ ported a hobby fastapi project into a lambda container and I can't speak highly enough about it. My costs went to zero, deployment is just as easy, performance went up (lambda is pretty good once warm), and my local dev build matches the API perfectly now. I could get some of that on vercel, but not the docker containerization, which makes all the local/remote stuff work the same.
I can tell you a good reason for it. At one company I was working for we had an API that we sold external access to as the back end for large health care providers websites and mobile apps.
But we also used it internally for batch processes.
In one case latency was important so we hosted the app in an auto scaling ECS Fargate cluster behind Nginx and in the other case throughput was important so we could just deploy the same API to Lambda.
The way I have done this in the past is to use an adapter library that maps from the incoming lambda event to whatever framework you are using (like fastify or jax-rs for example). Your code looks like the normal http request handler stuff you would normally write, but it isn’t running an http server inside the lambda beyond whatever stuff AWS does under the covers of course. I’ve deployed many Lambda based HTTP APIs in this pattern and its my preferred approach to using Lambda, though I would rather target a standard container orchestrator if available.
I'm confused, how does php-fpm connect someone to the right machine? It just looks like basic multiprocessing to me, which should be a basic feature of any decent http server.
Unless you're referring to the 'load balancer' in the comments where someone builds their own multiprocessing by launching multiple servers and putting nginx in front of it. I mean do what you need to do but at least be aware you're hacking together something that should be a basic feature of the http server.
If you wish to push me I'd be forced to admit that I don't like load balancers either, but that's because they're doing routing on the application layer which is not ideal and creates a single point of failure. That ship has sailed though.
I worked on a small SaaS that deployed in this way. The AWS bill was about 10x what it would have been if they had just deployed nodejs on an EC2 instance.
There's obviously a static load level where it makes more sense to have an always-on server vs. a FaaS and you need to monitor that boundary point.
The point of doing something like this "Lambda Monolith" is that transitioning to an always-on server is trivial. I've been doing this exact setup for a while and our static costs basically evaporated. Seeing your costs drop below a dollar/month on a project you are building is amazing. As soon as one of our projects is large enough, we move it to a dedicated instance or cluster. This allows us to delay that point until we have enough revenue to justify the costs.
I just can't get my head around this argument of 'scales to zero'.
If you have one or more professional developers working on a project how can you be bothered about an extra $20-$200/month when you know you'll also be spending a couple of engineering hours (worth more than $200) on migrating later?
The distant hum of hornets grows louder as you approach the HN thread.
There is no substitute for architecting your service for the market and with knowledge of the computing machinery (which boils down to physics) that will underpin it. By which I mean understanding how it will be used, how it will grow, which parts of it will require “structural strength” and which are “decorative” and how what you are developing will manage to align both with the customers requirements and what the physics of available computing machinery can provide.
I would argue that instead of starting with a Lambda Monolith and splitting routes out when they need to scale separately, you should be starting with an actual monolith and using Lambdas _only_ when a single route needs to scale separately (in a way that fits lambda). The Lambda Monolith is an unnecessary architecture as far as I'm concerned.
So a separate server running a monolith is not "unnecessary architecture", but a simple Lambda function is?
With a Lambda function you can have a dozen different versions of the same code running simultaneously with zero extra cost and none of them will affect each other's performance. Every one of them will be versioned and you can instantly roll back to any version or pick any version to be "production".
If you need multiple versions of something running simultaneously then ya lambda might be simpler.
In my experience, running a single monolith server will be much simpler than 20+ lambda "monoliths" that call each other. I think the simplicity of lambdas vs a persistent server looks good on paper but falls apart when you have multiple times more deployments to manage.
You can't if you have even moderately complex storage (like an SQL database). There is only one version of that, and while you can make sure that you can run one other version in parallel, it's just one version and a lot of extra complexity.
Just FYI: You can totally scale ECS down to zero. Our ECS bill hovers around $1/mo because we spin it up on demand based on queue size (It takes a painfully long time to spin up, though).
We figured out how to get Azure Functions to serve a complete webapp without any extra crap wrapped around it. No gateways/proxies/etc. One function that serves the root URL[0] and has conditionals for GET/POST methods. Beyond this point, anyone with old-school mastery of HTML/CSS/JS can get the rest of the job done with basic-ass SSR and multipart form posts.
For data, we just use Azure SQL Server. Authentication is like sticking legos together now. 100% managed identities, no magic strings, etc. Our functions get the user's claims principal right in the arg list. We have zero lines of authentication code in our latest products.
This stuff is absolutely the future for a vast majority of boring old business.
One thing to think about: If your FaaS offering is capable of serving content-type of application/json, is it not also capable of serving content-type of text/html? Do your providers go out of their way to prevent you from making a simple solve on 99% of B2B bullshit?
[0]: Note that serving the root URL on an Azure Function is an undocumented hack-around item. Worst case, we would serve the /app route and our users (B2B) wouldn't really care. My suspicion is that Microsoft detected our use case and saw that it stole a LOT of thunder from a wide array of other Azure offerings (API Gateway, Front Door, et. al.), so making it slightly more complicated (at first glance) is likely intentional.
Who monitors it 24/7 and checks the alerts? Who drives to the data center to fix broken hardware on Christmas Day? It has to be multiple "whos" or one sick leave will leave you completely vulnerable.
For small-medium companies whose main business isn't hosting software this makes it untenable from a financial point of view. For the monthly salary of a single SRE/devops/admin whatever you can run AWS services for a year at that scale.
We've got some experience with on-prem IT shops that have taken way more out of us than we probably should have allowed. Every one of their issues with getting our software to run in prod was unhappy in its own special way.
Our largest assets are SVG logos that our clients bring to the party. We do work with dynamic PDF documents, but these are uncachable for a number of reasons.
Hypothetically, if we had millions of users and static asset IO was actually causing trouble, we'd consider using a CDN or other relevant technology.
Services like Vercel just wrap the Lambda and indeed deploy an entire server to the Lambda and gained a lot of users this way. Lambda Monolith are good replacement to the old Heroky dynos. Lambda monolith are super cheap for B2B SaaS startups with little traffic
I'll extend this to all three cloud services, and dispute the assertion. Developers are smart and figured out that these serverless platforms are great for APIs even if the initial tutorials didn't present that scenario. Also, the platforms just got better at this over time while those early tutorials were somewhat cast in stone. I've not looked lately, but I would hope that they now have tutorials that show monolith scenarios.
>Lambda monolith are super cheap for B2B SaaS startups
Again, I'll extend this to Azure Functions and Cloud Run. Truly an amazing place we now sit. My first public facing API required me to build a physical machine and place it in a colo facility in town. Now I just run a command-line or check in my code and my API is live.
A big reason is that lambdas were half-baked and gradually became better. They are still limited.
Sending a binary blob? You have to convert it to base64.
Streaming a response? You can only do that on the nodejs runtime.
Establishing a short-term ws connection? Hard/impossible.
The model of "every function should be a separate Lambda" is just moronic - I've seen people run into hard limits on AWS going all-in on this model.
Instead Build a single executable/library and deploy it as a Lambda function.
Now you have automatic versioning, just push and it's a new version. You can label versions and call them based on labels.
Deploying to prod is just swapping the prod label to a new function. Want to roll back? Swap it back.
Credentials: ran a top10 mobile game backend on AWS Lambda with zero issues using a C# monolith.
Oh, you say you have more than 200 endpoints in your REST API gateway, and suddenly your CloudFormation stop working? Yes, unfortunately CF only load 8 pages of resources in alphabetical order when starting, and your root resource starts with a ‘Y’.
No problem, implement a new custom resource that just creates and discards API gateways until you have one with your desired root resource starting with ‘A-F’. Did I mention the ‘delete a rest api’ API is limited to a single call per minute? The fun doesn’t end. Now you may be able to grow until 600 resources before you’ll have to tighten the limits once again.
You say you think this is bollocks? Of course, just switch to an Application Load Balancer. Just 100 rules max means you’ll only need to nest about 4 of them to fit all your API endpoints.
And people wonder why some give up on the cloud. Any $5 VPS has higher limits than any of these AWS services…
That must've been a proper monolith then? =)
But we also used it internally for batch processes.
In one case latency was important so we hosted the app in an auto scaling ECS Fargate cluster behind Nginx and in the other case throughput was important so we could just deploy the same API to Lambda.
Yes I know about reserved concurrency.
Because it doesn't have to be this way, there's php-fpm and such that could eliminate the http->http step
Unless you're referring to the 'load balancer' in the comments where someone builds their own multiprocessing by launching multiple servers and putting nginx in front of it. I mean do what you need to do but at least be aware you're hacking together something that should be a basic feature of the http server.
If you wish to push me I'd be forced to admit that I don't like load balancers either, but that's because they're doing routing on the application layer which is not ideal and creates a single point of failure. That ship has sailed though.
The point of doing something like this "Lambda Monolith" is that transitioning to an always-on server is trivial. I've been doing this exact setup for a while and our static costs basically evaporated. Seeing your costs drop below a dollar/month on a project you are building is amazing. As soon as one of our projects is large enough, we move it to a dedicated instance or cluster. This allows us to delay that point until we have enough revenue to justify the costs.
If you have one or more professional developers working on a project how can you be bothered about an extra $20-$200/month when you know you'll also be spending a couple of engineering hours (worth more than $200) on migrating later?
> Seeing your costs drop below a dollar/month on a project you are building is amazing.
Honestly, this just means you don't have any users
Deleted Comment
With a Lambda function you can have a dozen different versions of the same code running simultaneously with zero extra cost and none of them will affect each other's performance. Every one of them will be versioned and you can instantly roll back to any version or pick any version to be "production".
In my experience, running a single monolith server will be much simpler than 20+ lambda "monoliths" that call each other. I think the simplicity of lambdas vs a persistent server looks good on paper but falls apart when you have multiple times more deployments to manage.
Deleted Comment
Source: I've rand both a Lambda Monolith and ECS on production and would pick Lambda any day
yes we have some very spiky workloads and we got bitten by that, subsequently we moved away from ECS for this exact reason