The current state of the framework deploy the entire project into a single lambda function instance. But for larger projects this can be a problem for several reasons:
The routes will be registered from each handler that will be implemented separately. Below is an example of the hello handler:
Example of usage:
app.py
from chalice import Chalice
app = Chalice(app_name="helloworld")
app.registrate_route(
name='hello_world',
path='/helloworld',
handler_class=HelloHandler,
)
hello_world.py
from chalice import LambdaHandler
class HelloWorldHandler(LambdaHandler):
def get(self):
return {"hello": "world"}
To make packaging possible, the project directory must be structured in a specific way.
as follows:
<project-dir>
โโโ helloworld
โ โโโ functionlib # function specific modules
โ โ โโโ __init__.py
โ โ โโโ utils.py
โ โโโ __init__.py
โ โโโ helloworld.py
โโโ chalicelib # project shared modules
โ โโโ __init__.py
โ โโโ generics.py
โโโ app.py
โโโ requirements.txt
โโโ etc ...
@jamesls thoughts?
Interesting. We've been using Blueprints to segment our routes. Perhaps that could be leveraged to generate the separate Lambda functions?
As far as the general idea of breaking out your rest API into multiple lambda functions, I am in favor of supporting this. I think it makes a lot of sense. There's a few guidelines I'd like to place on proposals being considered:
Just to throw another idea out there, what if there was no specific API for this? What if it was just a config option in .chalice/config.json (e.g "single_api_lambda": false). We would then create lambda functions with each new @app.route decorator representing a new lambda function. You can already configure which HTTP methods you want routed to it so it gives you the flexibility to group your lambda functions how you want. So for example:
from chalice import Chalice
app = Chalice(app_name="helloworld")
@app.route("/")
def index():
return {"hello": "world"}
@app.route("/foo")
def foo(): ...
@app.route("/bar", methods=["GET"])
def bar_get(): ...
@app.route("/bar", methods=["POST"])
def bar_post(): ...
The above app would create 4 lambda functions because there's 4 @app.route decorators. It also aligns more closely with how the existing @app.* decorators work, in that each decorator creates a new lambda function.
Implementation-wise this is going to be pretty challenging (a lot of stuff assumes APIHandler), but I'd rather the complication be in the implementation rather than in the user-facing API.
Thoughts?
cc @stealthycoin
Hey @jamesls, having one lambda function per route might take us from not having enough lambdas to having too many of them.
It's ok to have multiple methods in a single lambda function and it actually makes sense.
But it would be nice to have the ability to organize your api using different lambdas.
Maybe we can use the resource approach, but make it a new input for the route decorator:
```py
@app.route("/", methods=["GET"], resource="example_resource_1")
def get_1():
return {"hello_world": "this is a get"}
@app.route("/", methods=["POST"], resource="example_resource_1")
def post_1():
return {"hello_world": "this is a post"}
@app.route("/", methods=["GET"], resource="example_resource_2")
def get_2():
return {"hello_world": "this is a get"}
@app.route("/", methods=["POST"], resource="example_resource_2")
def post_2():
return {"hello_world": "this is a post"}
````
Because we have example_resource_1 and example_resource_2 we would end up with 2 lambda functions.
This seems like a really good pattern.
For me, I need to separate out my Read and Write Lambdas. At present, my Write endpoint handle thousands of writes per minute with only a few concurrent lambdas (3-8) - nice, but the Read endpoint is often sent complex queries which require long DB read times (inner joins and distincts over millions of records etc). At this point more lambdas are spun up cold for the Write endpoint and there is an unncessary cascading impact on performace. It would be great to have the whole application described in one project as above, as it is 'one' project and one API, but I want two Lambdas.
Should we gather the upvotes from https://github.com/aws/chalice/issues/513 too ?
Most helpful comment
Hey @jamesls, having one lambda function per route might take us from not having enough lambdas to having too many of them.
It's ok to have multiple methods in a single lambda function and it actually makes sense.
But it would be nice to have the ability to organize your api using different lambdas.
Maybe we can use the resource approach, but make it a new input for the route decorator:
```py
@app.route("/", methods=["GET"], resource="example_resource_1")
def get_1():
return {"hello_world": "this is a get"}
@app.route("/", methods=["POST"], resource="example_resource_1")
def post_1():
return {"hello_world": "this is a post"}
@app.route("/", methods=["GET"], resource="example_resource_2")
def get_2():
return {"hello_world": "this is a get"}
@app.route("/", methods=["POST"], resource="example_resource_2")
def post_2():
return {"hello_world": "this is a post"}
````
Because we have example_resource_1 and example_resource_2 we would end up with 2 lambda functions.