Sviluppare estensioni di lavoro Python per Funzioni di Azure
Funzioni di Azure consente di integrare comportamenti personalizzati come parte dell'esecuzione della funzione Python. Questa funzionalità consente di creare logica di business che i clienti possono usare facilmente nelle proprie app per le funzioni. Per altre informazioni, vedere il riferimento per sviluppatori Python. Le estensioni di lavoro sono supportate sia nei modelli di programmazione v1 che v2 Python.
In questa esercitazione si apprenderà come:
- Creare un'estensione di lavoro Python a livello di applicazione per Funzioni di Azure.
- Usare l'estensione in un'app nel modo in cui i clienti fanno.
- Pacchetto e pubblicazione di un'estensione per l'utilizzo.
Prerequisiti
Prima di iniziare, è necessario soddisfare questi requisiti:
Python 3.7 o versione successiva. Per controllare l'elenco completo delle versioni di Python supportate in Funzioni di Azure, vedere la guida per sviluppatori Python.
Il Funzioni di Azure Core Tools, versione 4.0.5095 o successiva, che supporta l'uso dell'estensione con il modello di programmazione Python v2. Controllare la versione con
func --version
.Visual Studio Code installato in una delle piattaforme supportate.
Creare l'estensione Python Worker
L'estensione creata segnala il tempo trascorso di una chiamata di trigger HTTP nei log della console e nel corpo della risposta HTTP.
Struttura di cartelle
La cartella per il progetto di estensione deve essere simile alla struttura seguente:
<python_worker_extension_root>/
| - .venv/
| - python_worker_extension_timer/
| | - __init__.py
| - setup.py
| - readme.md
Cartella/file | Descrizione |
---|---|
.venv/ | (Facoltativo) Contiene un ambiente virtuale Python usato per lo sviluppo locale. |
python_worker_extension/ | Contiene il codice sorgente dell'estensione di lavoro Python. Questa cartella contiene il modulo Python principale da pubblicare in PyPI. |
setup.py | Contiene i metadati del pacchetto di estensione del ruolo di lavoro Python. |
readme.md | Contiene le istruzioni e l'utilizzo dell'estensione. Questo contenuto viene visualizzato come descrizione nella home page del progetto PyPI. |
Configurare i metadati del progetto
Prima di tutto si crea setup.py
, che fornisce informazioni essenziali sul pacchetto. Per assicurarsi che l'estensione sia distribuita e integrata nelle app per le funzioni del cliente correttamente, verificare che 'azure-functions >= 1.7.0, < 2.0.0'
sia presente nella install_requires
sezione.
Nel modello seguente è necessario modificare author
, license
packages
author_email
install_requires
e url
i campi in base alle esigenze.
from setuptools import find_packages, setup
setup(
name='python-worker-extension-timer',
version='1.0.0',
author='Your Name Here',
author_email='your@email.here',
classifiers=[
'Intended Audience :: End Users/Desktop',
'Development Status :: 5 - Production/Stable',
'Intended Audience :: End Users/Desktop',
'License :: OSI Approved :: Apache Software License',
'Programming Language :: Python',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
],
description='Python Worker Extension Demo',
include_package_data=True,
long_description=open('readme.md').read(),
install_requires=[
'azure-functions >= 1.7.0, < 2.0.0',
# Any additional packages that will be used in your extension
],
extras_require={},
license='MIT',
packages=find_packages(where='.'),
url='https://your-github-or-pypi-link',
zip_safe=False,
)
Successivamente, si implementerà il codice di estensione nell'ambito a livello di applicazione.
Implementare l'estensione timer
Aggiungere il codice seguente in python_worker_extension_timer/__init__.py
per implementare l'estensione a livello di applicazione:
import typing
from logging import Logger
from time import time
from azure.functions import AppExtensionBase, Context, HttpResponse
class TimerExtension(AppExtensionBase):
"""A Python worker extension to record elapsed time in a function invocation
"""
@classmethod
def init(cls):
# This records the starttime of each function
cls.start_timestamps: typing.Dict[str, float] = {}
@classmethod
def configure(cls, *args, append_to_http_response:bool=False, **kwargs):
# Customer can use TimerExtension.configure(append_to_http_response=)
# to decide whether the elapsed time should be shown in HTTP response
cls.append_to_http_response = append_to_http_response
@classmethod
def pre_invocation_app_level(
cls, logger: Logger, context: Context,
func_args: typing.Dict[str, object],
*args, **kwargs
) -> None:
logger.info(f'Recording start time of {context.function_name}')
cls.start_timestamps[context.invocation_id] = time()
@classmethod
def post_invocation_app_level(
cls, logger: Logger, context: Context,
func_args: typing.Dict[str, object],
func_ret: typing.Optional[object],
*args, **kwargs
) -> None:
if context.invocation_id in cls.start_timestamps:
# Get the start_time of the invocation
start_time: float = cls.start_timestamps.pop(context.invocation_id)
end_time: float = time()
# Calculate the elapsed time
elapsed_time = end_time - start_time
logger.info(f'Time taken to execute {context.function_name} is {elapsed_time} sec')
# Append the elapsed time to the end of HTTP response
# if the append_to_http_response is set to True
if cls.append_to_http_response and isinstance(func_ret, HttpResponse):
func_ret._HttpResponse__body += f' (TimeElapsed: {elapsed_time} sec)'.encode()
Questo codice eredita da AppExtensionBase in modo che l'estensione si applica a ogni funzione nell'app. È anche possibile implementare l'estensione in un ambito a livello di funzione ereditando da FuncExtensionBase.
Il init
metodo è un metodo di classe chiamato dal ruolo di lavoro quando viene importata la classe di estensione. È possibile eseguire azioni di inizializzazione qui per l'estensione. In questo caso, viene inizializzata una mappa hash per registrare l'ora di inizio della chiamata per ogni funzione.
Il configure
metodo è rivolto al cliente. Nel file readme è possibile indicare ai clienti quando devono chiamare Extension.configure()
. Il readme deve inoltre documentare le funzionalità di estensione, la possibile configurazione e l'utilizzo dell'estensione. In questo esempio, i clienti possono scegliere se il tempo trascorso viene segnalato in HttpResponse
.
Il pre_invocation_app_level
metodo viene chiamato dal ruolo di lavoro Python prima dell'esecuzione della funzione. Fornisce le informazioni della funzione, ad esempio contesto di funzione e argomenti. In questo esempio l'estensione registra un messaggio e registra l'ora di inizio di una chiamata in base al relativo invocation_id.
Analogamente, viene chiamato dopo l'esecuzione della post_invocation_app_level
funzione. In questo esempio viene calcolato il tempo trascorso in base all'ora di inizio e all'ora corrente. Sovrascrive anche il valore restituito della risposta HTTP.
Creare un readme.md
Creare un file readme.md nella radice del progetto di estensione. Questo file contiene le istruzioni e l'utilizzo dell'estensione. Il contenuto readme.md viene visualizzato come descrizione nella home page del progetto PyPI.
# Python Worker Extension Timer
In this file, tell your customers when they need to call `Extension.configure()`.
The readme should also document the extension capabilities, possible configuration,
and usage of your extension.
Usare l'estensione in locale
Dopo aver creato un'estensione, è possibile usarla in un progetto di app per verificare che funzioni come previsto.
Creare una funzione trigger HTTP
Creare una nuova cartella per il progetto dell'app e spostarla.
Dalla shell appropriata, ad esempio Bash, eseguire il comando seguente per inizializzare il progetto:
func init --python
Usare il comando seguente per creare una nuova funzione trigger HTTP che consente l'accesso anonimo:
func new -t HttpTrigger -n HttpTrigger -a anonymous
Attivare un ambiente virtuale
Creare un ambiente virtuale Python basato sul sistema operativo come indicato di seguito:
Attivare l'ambiente virtuale Python, in base al sistema operativo come indicato di seguito:
Configurare l'estensione
Installare pacchetti remoti per il progetto dell'app per le funzioni usando il comando seguente:
pip install -r requirements.txt
Installare l'estensione dal percorso del file locale, in modalità modificabile come indicato di seguito:
pip install -e <PYTHON_WORKER_EXTENSION_ROOT>
In questo esempio sostituire
<PYTHON_WORKER_EXTENSION_ROOT>
con il percorso radice del progetto di estensione.Quando un cliente usa l'estensione, aggiungerà invece il percorso del pacchetto di estensione al file requirements.txt, come negli esempi seguenti:
Aprire il file di progetto local.settings.json e aggiungere il campo seguente a
Values
:"PYTHON_ENABLE_WORKER_EXTENSIONS": "1"
Quando si esegue in Azure, si aggiunge
PYTHON_ENABLE_WORKER_EXTENSIONS=1
invece alle impostazioni dell'app nell'app per le funzioni.Aggiungere due righe seguenti prima della
main
funzione nel file __init.py__ per il modello di programmazione v1 o nel file function_app.py per il modello di programmazione v2:from python_worker_extension_timer import TimerExtension TimerExtension.configure(append_to_http_response=True)
Questo codice importa il
TimerExtension
modulo e imposta il valore diappend_to_http_response
configurazione.
Verificare l'estensione
Dalla cartella radice del progetto dell'app avviare l'host della funzione usando
func host start --verbose
. Verrà visualizzato l'endpoint locale della funzione nell'output comehttps://localhost:7071/api/HttpTrigger
.Nel browser inviare una richiesta GET a
https://localhost:7071/api/HttpTrigger
. Verrà visualizzata una risposta simile alla seguente, con i dati TimeElapsed per la richiesta aggiunta.This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response. (TimeElapsed: 0.0009996891021728516 sec)
Pubblicare l'estensione
Dopo aver creato e verificato l'estensione, è comunque necessario completare queste attività di pubblicazione rimanenti:
- Scegliere una licenza.
- Creare una readme.md e altre documentazione.
- Pubblicare la libreria di estensioni in un registro pacchetti Python o in un sistema di controllo della versione (VCS).
Per pubblicare l'estensione in PyPI:
Eseguire il comando seguente per installare
twine
ewheel
nell'ambiente Python predefinito o in un ambiente virtuale:pip install twine wheel
Rimuovere la cartella precedente
dist/
dal repository dell'estensione.Eseguire il comando seguente per generare un nuovo pacchetto all'interno
dist/
di :python setup.py sdist bdist_wheel
Eseguire il comando seguente per caricare il pacchetto in PyPI:
twine upload dist/*
Potrebbe essere necessario specificare le credenziali dell'account PyPI durante il caricamento. È anche possibile testare il caricamento del pacchetto con
twine upload -r testpypi dist/*
. Per altre informazioni, vedere la documentazione di Twine.
Dopo questi passaggi, i clienti possono usare l'estensione includendo il nome del pacchetto nella requirements.txt.
Per altre informazioni, vedere l'esercitazione ufficiale sulla creazione di pacchetti Python.
Esempio
È possibile visualizzare il progetto di estensione di esempio completato da questo articolo nel repository di esempio python_worker_extension_timer .
L'integrazione di OpenCensus è un progetto open source che usa l'interfaccia di estensione per integrare la traccia dei dati di telemetria nelle app Python Funzioni di Azure. Vedere il repository opencensus-python-extensions-azure per esaminare l'implementazione di questa estensione del ruolo di lavoro Python.
Passaggi successivi
Per altre informazioni sullo sviluppo di Funzioni di Azure Python, vedere le risorse seguenti: