Deploy Python functions

πŸ‘

What you'll learn

  • Deploying your python functions via servicefoundry

This is a guide to deploy Python functions as a Service using servicefoundry.

Project structure

To complete this guide, you are going to create the following files:

  • module.py: contains our functions.
  • deploy.py: contains our deployment code.
  • requirements.txt: contains our dependencies.
  • send_request.py: contains the code to interact with the service

Your final file structure is going to look like this:

.
β”œβ”€β”€ module.py
β”œβ”€β”€ deploy.py
β”œβ”€β”€ requirements.txt
└── send_request.py

As you can see, all the following files are created in the same folder/directory.

Step 1: Writing the functions we will deploy

File Structure:

.
β”œβ”€β”€ module.py
└── requirements.txt

πŸ“˜

Note

  1. Your functions should be locally importable.
  2. The inputs and return type of your function must be type annotated. See https://docs.python.org/3/library/typing.html for additional reference.
  3. The data type of the inputs and return values of the function should be json serialisable types.

These include:

  • None (See Optional in Python type hints)
  • str
  • int
  • bool
  • float
  • List
  • Dict

module.py

from typing import List

import numpy as np


def normal(loc: float, scale: float, size: List[int]):
    return np.random.normal(loc=loc, scale=scale, size=size).tolist()


def uniform(low: float, high: float, size: List[int]):
    return np.random.uniform(low=low, high=high, size=size).tolist()

requirements.txt

numpy==1.23.2

Step 2: Deploying the functions as a service

You can deploy services on TrueFoundry programmatically either using our Python SDK

File Structure:

.
β”œβ”€β”€ module.py
β”œβ”€β”€ requirements.txt
└── deploy.py
  • Here we will use the FunctionService class from servicefoundry library to define and deploy the service.
  • We can use the register_function method to register the functions we want to deploy.
  • In the example below, the deployed service will have two different HTTP POST APIs. One for normal and another for the uniform function.
  • While deploying, we automatically install the requirements defined in the requirements.txt file.

πŸ“˜

Note:

You can also run the service locally using service.run().join()

deploy.py

import argparse
import logging

from servicefoundry.function_service import FunctionService

from module import normal, uniform

logging.basicConfig(level=logging.INFO)

parser = argparse.ArgumentParser()
parser.add_argument("--workspace_fqn", required=True, type=str)
args = parser.parse_args()

service = FunctionService(name="func-service")
service.register_function(normal)
service.register_function(uniform)

service.deploy(workspace_fqn=args.workspace_fqn)

πŸ“˜

Note

Before running the command given below, for deploying functions as a service, you need to install all the dependencies locally.

For that run the following command: pip install -r requirements.txt

You can deploy using the following command by passing in your workspace FQN.

python deploy.py --workspace_fqn "<YOUR-WORKSPACE-FQN>"

🚧

Important

The above command will only upload the contents of the current directory. Therefore, when you import the function/module for registration, ensure that the import statement is relative to the directory from where you are deploying.

Interacting with the service

After you deploy the service, you will get an output like below,

deployment/function/simple-function-deployment on ξ‚  main [?] via 🐍 v3.9.13 (venv) took 10s
❯ python deploy.py
INFO:servicefoundry:Function 'normal' from module 'module' will be deployed on path 'POST /normal'.
INFO:servicefoundry:Function 'uniform' from module 'module' will be deployed on path 'POST /uniform'.
INFO:servicefoundry:Deploying application 'func-service' to 'v1:local:my-ws-2'
INFO:servicefoundry:Uploading code for service 'func-service'
INFO:servicefoundry:Uploading contents of '/Users/debajyotichatterjee/work/truefoundry-examples/deployment/function/simple-function-deployment'
INFO:servicefoundry:.tfyignore not file found! We recommend you to create .tfyignore file and add file patterns to ignore
INFO:servicefoundry:Deployment started for application 'func-service'. Deployment FQN is 'v1:local:my-ws-2:func-service:v3'
INFO:servicefoundry:Service 'func-service' will be available at
'https://func-service-my-ws-2.tfy-ctl-euwe1-devtest.devtest.truefoundry.tech'
after successful deployment
INFO:servicefoundry:You can find the application on the dashboard:- 'https://app.devtest.truefoundry.tech/applications/cl84s4md500921qruhysegp5x?tab=deployments'

You can find the host of the deployed service in the following section in the above logs.

INFO:servicefoundry:Service 'func-service' will be available at
'https://func-service-my-ws-2.tfy-ctl-euwe1-devtest.devtest.truefoundry.tech'
after successful deployment

πŸ“˜

Note

Swagger API documentation will be available on the root path.

Click on the host link to open the docs

Now we will create the send_request.py file, which is responsible for sending a request with our data to the service, and giving us the response.

File Structure:

.
β”œβ”€β”€ module.py
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ deploy.py
└── send_request.py

send_request.py

You can send requests to the deployed service by using the code snippet below. Pass the host using the --host command line argument.

import argparse
from urllib.parse import urljoin

import requests

parser = argparse.ArgumentParser()
parser.add_argument("--host", required=True, type=str)
args = parser.parse_args()

response = requests.post(
    urljoin(args.host, "/normal"),
    json={"loc": 0, "scale": 1, "size": [12, 1]}
)
print(response.json())

response = requests.post(
    urljoin(args.host, "/uniform"), 
    json={"low": 0, "high": 1, "size": [12, 1]}
)
print(response.json())