There is a tight relationship between application development and the compute it will run on. There are costs and considerations of choosing whether to go with Serverless Compute by default or not.
The lower your application invocation ratio is, the better it is to go with Functions as it will be more cost effective. That is true both to the “product level” and the “application level”. As you’d be paying your cloud provider per request and according to throughput, this is how’d you’d literally pay for a mistake in a choice between the two, maybe even gravely
Meeting throughput can be achieved either through scaling infrastructure or within the application itself. Both Containers and Functions are passing throughput and scaling control towards infrastructure, but they do so differently and they also scale differently.
When a Function is idle, not handling any incoming requests, it is frozen and later thawed. When not enough Functions instances are available, the infrastructure would then launch a new one. Alas, launching a new one can take from a few hundred milliseconds to a few seconds. Expect a substantiated lag could affect your customers for a while. You must first ask yourself if it even has an effect your end customers.
Functions can not retain any state, thus applications running within must be stateless. Containers can be stateful, but should not. Stateless applications are more reliable and resilient than stateful ones. But depending on the use case it may be marginally.
Functions do not have a shutdown hook, can shutdown unpredictably and can easily scale fast to thousands of instances. This will require you to consider the aspect of persistent connections while considering to work with Functions. It could also affect your application’s external dependencies / database of choice.
A Function’s interconnectedness with other services of your cloud provider is one of its beauties. It can save you a lot of unnecessary, repetitive coding of integrating with other infrastructure cloud services. The presented use cases would have you better understand how to decouple applications, when and why it would be better to use a Function and one day to integrate with other custom infrastructure components. As it is embedded into the infrastructure layer, it is reusable between multiple applications.
There are some tasks that are just impossible to do with Functions either because the function model inherently prohibits you or due to technical limitations. There are a few more general development and refactoring related concerns and tradeoffs.