Serverless Functions

At the heart of Cdev is the Serverless Function. This is the most powerful resource available through the framework because it is where you have to freedom to create what you want. We have made many optimizations to create the best experience for creating and maintaining Serverless Functions.

For a more in depth discussion about the capabilities and limits of Serverless Functions checkout our architecture documentation


Basic Function

    
from cdev.resources.simple.xlambda import simple_function_annotation @simple_function_annotation("hello_function") def hello_world(event, context): print('Hello World')
Basic Function

The component that contains the function is registered in src/cdev_project.py.

# Generated as part of Quick Start project template
import os

from cdev.default.cloudmapper import DefaultMapper
from cdev.default.components import Cdev_FileSystem_Component

from cdev import Project as cdev_project

myProject = cdev_project.instance()


myProject.add_mapper(DefaultMapper())

# register hello_world component
myProject.add_component(
    Cdev_FileSystem_Component(os.path.join("src", "hello_world"), "hello_world_comp")
)

Once your function is deployed, you can execute it with the cdev run function.execute command.

cdev run function.execute <component_name>.hello_function

You can then look at the logs from the deployed function

cdev run function.logs <component_name>.hello_function

As you are working on a Function, you can use the --watch flag to have live updated feed of your logs

cdev run function.logs <component_name>.hello_function --watch

Note that it may take a second for the logs to show up since they are being pulled from the cloud.

Commands available for functions

You can get the available commands for Serverless Functions by running:

cdev run function -h 

Responding to Events

One of the most important aspects of Serverless Functions is that they can be triggered by different Events. By passing an Event construct into the args of your Serverless Function, your deployed Serverless Function will be triggered by the event in the Cloud. The following demonstrates a Serverless Function being hooked up to an API Route Event.

    
import json from cdev.resources.simple.xlambda import simple_function_annotation from cdev.resources.simple.api import Api, route_verb myApi = Api("demo") hello_route = myApi.route("/hello", route_verb.GET) @simple_function_annotation("hello_function", events=[hello_route.event()]) def hello_world(event, context): print(event) message = "Hello!" return { "isBase64Encoded": False, "statusCode": 200, "body": json.dumps(message), "headers": { "content-type": "application/json" } }

You can now get the url of the created API and execute your function by going to the /hello route.

cdev output <component_name>.api.demo.endpoint

You can use the command line tool curl to test your live url or

curl <api_endpoint>/hello

You can even go to the url in your favorite web browser!

After visiting the url you can also checkout the logs of your Function to see the information that is passed to your Function about the Event that triggered it.

cdev run function.logs <component_name>.hello_function

Permissions

By default, a created Function has no permissions to access other resources, so you have to provide permissions to your Function for it to be able to access other resources. Other resources will have properties that define the set of Permissions available to be granted to a Function.

    
import boto3 from cdev.resources.simple.xlambda import simple_function_annotation from cdev.resources.simple.object_store import Bucket myBucket = Bucket("demo_bucket") s3_client = boto3.client('s3') @simple_function_annotation("hello_function", permissions=[myBucket.available_permissions.READ_AND_WRITE_BUCKET]) def hello_world(event, context): bucket_name = "BUCKET_NAME" print( s3_client.list_objects( Bucket=bucket_name ).get('Contents') )


Environment Variables

Although the above Function has permission to access the Bucket, it does not by default know the name of the Bucket. All functions have a set of Environment Variables that can be set. To access these variables within the Serverless Function use the os.environ variable.

    
import boto3 import os from cdev.resources.simple.xlambda import simple_function_annotation from cdev.resources.simple.object_store import Bucket myBucket = Bucket("demo_bucket") s3_client = boto3.client('s3') @simple_function_annotation("hello_function", permissions=[myBucket.available_permissions.READ_AND_WRITE_BUCKET], environment={"BUCKET_NAME": myBucket.output.bucket_name}) def hello_world(event, context): bucket_name = os.environ.get("BUCKET_NAME") print(bucket_name) print( s3_client.list_objects( Bucket=bucket_name ).get('Contents') )


Third Party Packages

Third Party Packages are an important part of modern software development. To use a third party package, simple install it with pip (we highly recommend using a virtual python environment) and then use the package in a function.

pip install pandas
    
import pandas from cdev.resources.simple.xlambda import simple_function_annotation from cdev.resources.simple.object_store import Bucket @simple_function_annotation("hello_function") def hello_world(event, context): print(pandas) print("Hey friends")

It might take a few seconds to upload a copy of the dependency to the cloud when first used, but when using the package in other functions in the same component, it will simply link to the already deployed version.

    
import pandas from cdev.resources.simple.xlambda import simple_function_annotation from cdev.resources.simple.object_store import Bucket @simple_function_annotation("hello_function") def hello_world(event, context): print(pandas) print("Hey friends") @simple_function_annotation("hello_function2") def hello_world2(event, context): print(pandas) print("Hey friends from a different function")