Cdev provides optimizations that are designed to make creating and managing Serverless Functions a seamless experience.
One of the biggest problems when migrating to a Serverless Compute
platform is having to think about how the change in the underlying platform creates problems like cold starts.
Cdev introduces a set of parsing tools that attempt to understand the dependencies of a Serverless function, so that it can deploy only the needed dependencies of the function. To understand Cdev’s parsing technology, it helps to start with an example and understand all the parts that can add time to a Cold Start. In the example, there are three handler functions that each interact with a different external AWS service, but they are part of the same backend and make sense to be kept in the same file.
import boto3 dynamodb_client = boto3.client("dynamodb") s3_client = boto3.client("s3") sqs_client = boto3.client("sqs") def MyHandler1(event, context): # This function connects to a dynamodb table to look # up information and return it to the user # info = dynamodb_client.lookup(event.get("user_id")) # Other code # # # return info def MyHandler2(event, context): # This function gets an object from s3 and returns it to the user object = s3_client.get_object(event.get("item_key")) # Other Code # # # return object def MyHandler3(event, context): # This function creates an item in an sqs queue that triggers downstream tasks sqs_client.put_item(event.get("sqs_event")) return {}
When a python module is loaded, all the code in the top level namespace is executed, which means for our function, it executes all three boto3.client calls. These extra global statements adds unnecessary time to each function’s Cold Start because each function only uses a single external AWS service, but a connection is made to each of the external AWS services. Connections to these external systems add extra latency because the initial creation of the connection require round trips between the systems before communication can start.
By analyzing the syntax tree representation of the code, Cdev is able to understand what parts of the global namespace are needed for each individual function. With this understanding, we can parse each individual handler function along with the needed global statements into a separate file. These newly created files can be used as the deployment final artifact.
For the above example, the final deployment artifacts using Cdev would be:
myhandler1.py
import boto3 dynamodb_client = boto3.client("dynamodb") def MyHandler1(event, context): # This function connects to a dynamodb table to look # up information and return it to the user # info = dynamodb_client.lookup(event.get("user_id")) # Other code # # # return info
myhandler2.py
import boto3 s3_client = boto3.client("s3") def MyHandler2(event, context): # This function gets an object from s3 and returns it to the user object = s3_client.get_object(event.get("item_key")) # Other Code # # # return object
myhandler3.py
import boto3 sqs_client = boto3.client("sqs") def MyHandler3(event, context): # This function creates an item in an sqs queue that triggers downstream tasks sqs_client.put_item(event.get("sqs_event")) return {}
Using the intermediate files as the deployment artifacts also allows for fine grain tracking of changes to each individual function. Without this optimization, updates to a global statement
would cause an update to all function handlers within the file.
Another benefit of this function parsing is that it removes code that contains cdev
resource definitions from the final deployed artifact. For example in the follow code from the quick-start
template, the definition of the API
is removed from the final deployment artifact.
Serverless Function
. Resources are designed to interact with the Cdev
framework during the building of a project, but they are designed to be called at runtime. Information about resources should be passed to functions via environment variables.from cdev.aws.api import Api from cdev.aws.lambda_function import ServerlessFunction from cdev import Project as cdev_project myProject = cdev_project.instance() DemoApi = Api("demoapi") hello_route = DemoApi.route("/hello_world", "GET") @ServerlessFunction("hello_world_function", events=[hello_route.event()]) def hello_world(event, context): print("Hello from inside your Function! 👋") return "Hello World! 🚀" myProject.display_output("Base API URL", DemoApi.output.endpoint) myProject.display_output("Routes", DemoApi.output.endpoints)
One of the biggest challenges of Serverless Development is managing the bundling of third-party packages with your project. Cdev automatically detects and deploys third party packages used by functions.
Due to limitations of the underlying platforms around total package size and to reduce cold starts, it is important that a function only contains the dependencies that are used. Using the parsed functions artifacts, Cdev is able to analyze and compute the dependencies of each individual function and link only the needed dependencies.
Projects often encapsulate and share functionality throughout a project as relative dependencies. Cdev automatically analyzes the relative imports used by a function and packages the needed relative dependencies with the deployment artifact.
src
directory. Cdev only supports referencing dependencies that are either installed via a package manager or referenced as relative dependencies using the dot notation.To learn more about the capabilities of Serverless Functions checkout our resource guide.