import json def handler(event, context): evt = json.loads(event) result = 'hello %s' % evt.get('name', 'world') return result
- Cons: you can't assume it's JSON.
- Pros: the platform doesn't force you to convert your non-JSON thing to JSON format.
e.g. You can pass protobuf format event or an image file to the function, the platform just passes the event to the handler without any examination/transformation. The protobuf and type checking idea mentioned by @timallenwagner can be partially satisfied.
By contrast, if the event is JSON type, to pass a binary value, it needs to be converted to something like base64 encoded and formed into a JSON string, passed to the service which converts it to dict, and then passed to the handler which converts it to the binary.
The return value is not restricted to JSON either for the same reason.
Next you will also see the familiar HTTP (req/resp) interface in the programming model. Why? Because using JSON to describe request is tedious/inefficient and not native to the web development.
If you look at tools around Lambda, you see many frameworks/platforms trying to give the HTTP interface back to the developer, e.g.@vercel now, @tjholowaychukup. It's doable but not quite nice. The shim approach also needs to deal with the event and request/response conversion, which is an overhead.
The Function Compute (FC) service avoids that by exposing the HTTP function interface, e.g. Python WSGI, NodeJS express, Java servlet etc. It not only avoids the unnecessary transformation overhead, but also brings the native experience back. Running a Django or Flask app on FC requires just few lines of code.
Is this enough? Customers also ask for more runtime support. The custom runtime approach seems the way to go. But what interface the custom runtime should expose? Like the event function model?
Pure functions may look cool, but writing a webserver based application isn't a headache for many languages. By contrast, converting a webserver based application to pure functions requires a lot of work, not to mention the overhead between the event and HTTP request.
- It further eases the migration of web applications (e.g. alibabacloud.com/help/doc-detai⋯).
- Anyone can use this simple approach to write functions. Maybe it's not a good name cause the function and runtime are bundled together.
One more thing, you can have an optional initializer handler. It's a good place to do some preparation work, e.g. initializing HTTP/DB client. This has been asked by @theburningmonk, @timallenwagner and more. It not only makes the code a bit cleaner, but also reduces the cold-start time. I've been seeing vendors working hard to reduce the platform cold-start, e.g. how to get the function instance up and running quickly.
import time time.sleep(5) def handler(event, context): time.sleep(2) return ''
If I invoke this function twice concurrently, there will be 2 cold-starts.
import time def initializer(context): time.sleep(5) def handler(event, context): time.sleep(2) return ''
If I invoke the function twice concurrently, there will be 1 cold-start. Why? because the 1st function instance becomes available earlier and hence serves the 2nd request while the 2nd instance is still being initialized.
This is just one example that shows how the initializer can be used to reduce cold-start latency. There are more optimizations that can be done in the background, e.g. updating functions also triggers instance update. A bit more info can be found here.
This concludes the current state of Function Compute programming model. Will there be more styles? Maybe, let us know what you need.