GitHub - GoogleCloudPlatform/functions-framework-python: FaaS (Function as a service) framework for writing portable Python functions (original) (raw)
Functions Framework for Python
An open source FaaS (Function as a service) framework for writing portable Python functions -- brought to you by the Google Cloud Functions team.
The Functions Framework lets you write lightweight functions that run in many different environments, including:
- Google Cloud Run Functions
- Your local development machine
- Knative-based environments
The framework allows you to go from:
def hello(request): return "Hello world!"
To:
curl http://my-url
Output: Hello world!
All without needing to worry about writing an HTTP server or complicated request handling logic.
Features
- Spin up a local development server for quick testing
- Invoke a function in response to a request
- Automatically unmarshal events conforming to the CloudEvents spec
- Portable between serverless platforms
Installation
Install the Functions Framework via pip
:
pip install functions-framework
Or, for deployment, add the Functions Framework to your requirements.txt
file:
Quickstarts
Quickstart: HTTP Function (Hello World)
Create an main.py
file with the following contents:
import flask import functions_framework
@functions_framework.http def hello(request: flask.Request) -> flask.typing.ResponseReturnValue: return "Hello world!"
Your function is passed a single parameter,
(request)
, which is a Flask Request object.
Run the following command:
functions-framework --target hello --debug
- Serving Flask app "hello" (lazy loading)
- Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
- Debug mode: on
- Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)
(You can also use functions-framework-python
if you have multiple language frameworks installed).
Open http://localhost:8080/ in your browser and see Hello world!.
Or send requests to this function using curl
from another terminal window:
curl localhost:8080
Output: Hello world!
Quickstart: CloudEvent Function
Create an main.py
file with the following contents:
import functions_framework from cloudevents.http.event import CloudEvent
@functions_framework.cloud_event def hello_cloud_event(cloud_event: CloudEvent) -> None: print(f"Received event with ID: {cloud_event['id']} and data {cloud_event.data}")
Your function is passed a single CloudEvent parameter.
Run the following command to run hello_cloud_event
target locally:
functions-framework --target=hello_cloud_event
In a different terminal, curl
the Functions Framework server:
curl -X POST localhost:8080
-H "Content-Type: application/cloudevents+json"
-d '{
"specversion" : "1.0",
"type" : "example.com.cloud.event",
"source" : "https://example.com/cloudevents/pull",
"subject" : "123",
"id" : "A234-1234-1234",
"time" : "2018-04-05T17:31:00Z",
"data" : "hello world"
}'
Output from the terminal running functions-framework
:
Received event with ID: A234-1234-1234 and data hello world
More info on sending CloudEvents payloads, see examples/cloud_run_cloud_events instruction.
Quickstart: Error handling
The framework includes an error handler that is similar to theflask.Flask.errorhandlerfunction, which allows you to handle specific error types with a decorator:
import functions_framework
@functions_framework.errorhandler(ZeroDivisionError) def handle_zero_division(e): return "I'm a teapot", 418
def function(request): 1 / 0 return "Success", 200
This function will catch the ZeroDivisionError
and return a different response instead.
Quickstart: Pub/Sub emulator
- Create a
main.py
file with the following contents:
def hello(event, context):
print("Received", context.event_id) - Start the Functions Framework on port 8080:
functions-framework --target=hello --signature-type=event --debug --port=8080 - In a second terminal, start the Pub/Sub emulator on port 8085.
export PUBSUB_PROJECT_ID=my-project
gcloud beta emulators pubsub start \
--project=$PUBSUB_PROJECT_ID \
--host-port=localhost:8085
You should see the following after the Pub/Sub emulator has started successfully:
[pubsub] INFO: Server started, listening on 8085
- In a third terminal, create a Pub/Sub topic and attach a push subscription to the topic, using
http://localhost:8080
as its push endpoint. Publish some messages to the topic. Observe your function getting triggered by the Pub/Sub messages.
export PUBSUB_PROJECT_ID=my-project
export TOPIC_ID=my-topic
export PUSH_SUBSCRIPTION_ID=my-subscription
$(gcloud beta emulators pubsub env-init)
git clone https://github.com/googleapis/python-pubsub.git
cd python-pubsub/samples/snippets/
pip install -r requirements.txt
python publisher.py PUBSUBPROJECTIDcreatePUBSUB_PROJECT_ID create PUBSUBPROJECTIDcreateTOPIC_ID
python subscriber.py PUBSUBPROJECTIDcreate−pushPUBSUB_PROJECT_ID create-push PUBSUBPROJECTIDcreate−pushTOPIC_ID $PUSH_SUBSCRIPTION_ID http://localhost:8080
python publisher.py PUBSUBPROJECTIDpublishPUBSUB_PROJECT_ID publish PUBSUBPROJECTIDpublishTOPIC_ID
You should see the following after the commands have run successfully:
Created topic: projects/my-project/topics/my-topic
topic: "projects/my-project/topics/my-topic"
push_config {
push_endpoint: "http://localhost:8080"
}
ack_deadline_seconds: 10
message_retention_duration {
seconds: 604800
}
.
Endpoint for subscription is: http://localhost:8080
1
2
3
4
5
6
7
8
9
Published messages to projects/my-project/topics/my-topic.
And in the terminal where the Functions Framework is running:
* Serving Flask app "hello" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: on
* Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)
* Restarting with fsevents reloader
* Debugger is active!
* Debugger PIN: 911-794-046
Received 1
127.0.0.1 - - [11/Aug/2021 14:42:22] "POST / HTTP/1.1" 200 -
Received 2
127.0.0.1 - - [11/Aug/2021 14:42:22] "POST / HTTP/1.1" 200 -
Received 5
127.0.0.1 - - [11/Aug/2021 14:42:22] "POST / HTTP/1.1" 200 -
Received 6
127.0.0.1 - - [11/Aug/2021 14:42:22] "POST / HTTP/1.1" 200 -
Received 7
127.0.0.1 - - [11/Aug/2021 14:42:22] "POST / HTTP/1.1" 200 -
Received 8
127.0.0.1 - - [11/Aug/2021 14:42:22] "POST / HTTP/1.1" 200 -
Received 9
127.0.0.1 - - [11/Aug/2021 14:42:39] "POST / HTTP/1.1" 200 -
Received 3
127.0.0.1 - - [11/Aug/2021 14:42:39] "POST / HTTP/1.1" 200 -
Received 4
127.0.0.1 - - [11/Aug/2021 14:42:39] "POST / HTTP/1.1" 200 -
For more details on extracting data from a Pub/Sub event, seehttps://cloud.google.com/functions/docs/tutorials/pubsub#functions_helloworld_pubsub_tutorial-python
Quickstart: Build a Deployable Container
- Install Docker and the pack tool.
- Build a container from your function using the Functions buildpacks:
pack build \
--builder gcr.io/buildpacks/builder:v1 \
--env GOOGLE_FUNCTION_SIGNATURE_TYPE=http \
--env GOOGLE_FUNCTION_TARGET=hello \
my-first-function
- Start the built container:
docker run --rm -p 8080:8080 my-first-function
# Output: Serving function...
- Send requests to this function using
curl
from another terminal window:
curl localhost:8080
# Output: Hello World!
Run your function on serverless platforms
Google Cloud Run functions
This Functions Framework is based on the Python Runtime on Google Cloud Functions.
On Cloud Functions, using the Functions Framework is not necessary: you don't need to add it to your requirements.txt
file.
After you've written your function, you can simply deploy it from your local machine using the gcloud
command-line tool. Check out the Cloud Functions quickstart.
Container environments based on Knative
Cloud Run and Cloud Run on GKE both implement the Knative Serving API. The Functions Framework is designed to be compatible with Knative environments. Just build and deploy your container to a Knative environment.
Configure the Functions Framework
You can configure the Functions Framework using command-line flags or environment variables. If you specify both, the environment variable will be ignored.
Command-line flag | Environment variable | Description |
---|---|---|
--host | HOST | The host on which the Functions Framework listens for requests. Default: 0.0.0.0 |
--port | PORT | The port on which the Functions Framework listens for requests. Default: 8080 |
--target | FUNCTION_TARGET | The name of the exported function to be invoked in response to requests. Default: function |
--signature-type | FUNCTION_SIGNATURE_TYPE | The signature used when writing your function. Controls unmarshalling rules and determines which arguments are used to invoke your function. Default: http; accepted values: http, event or cloudevent |
--source | FUNCTION_SOURCE | The path to the file containing your function. Default: main.py (in the current working directory) |
--debug | DEBUG | A flag that allows to run functions-framework to run in debug mode, including live reloading. Default: False |
Enable Google Cloud Run function Events
The Functions Framework can unmarshall incoming Google Cloud Run functions event payloads to event
and context
objects. These will be passed as arguments to your function when it receives a request. Note that your function must use the event
-style function signature:
def hello(event, context): print(event) print(context)
To enable automatic unmarshalling, set the function signature type to event
using the --signature-type
command-line flag or the FUNCTION_SIGNATURE_TYPE
environment variable. By default, the HTTP signature will be used and automatic event unmarshalling will be disabled.
For more details on this signature type, see the Google Cloud Functions documentation onbackground functions.
See the running example.
Advanced Examples
More advanced guides can be found in the examples/ directory. You can also find examples on using the CloudEvent Python SDK here.
Contributing
Contributions to this library are welcome and encouraged. See CONTRIBUTING for more information on how to get started.