Développer des extensions de Worker Python pour Azure Functions
Avec Azure Functions vous intégrez des comportements personnalisés dans le cadre de l’exécution d’une fonction Python. Cette fonctionnalité vous permet de créer une logique métier que les clients peuvent facilement utiliser dans leurs propres applications de fonction. Pour en savoir plus, consultez les Informations de référence pour les développeurs Python. Les extensions du Worker sont prises en charge dans les modèles de programmation Python v1 et v2.
Ce didacticiel vous montre comment effectuer les opérations suivantes :
- Créer une extension de Worker Python au niveau de l’application pour Azure Functions.
- Consommer votre extension dans une application de la même façon que vos clients.
- Empaqueter et publier une extension pour la consommation.
Prérequis
Avant de commencer, vous devez satisfaire aux exigences suivantes :
Python 3.7 ou version ultérieure. Pour connaître la liste complète des versions de Python prises en charge dans Azure Functions, consultez le Guide du développeur Python.
L’ensemble d’outils Azure Functions Core Tools, version 4.0.5095 ou ultérieure, qui prend en charge l’utilisation de l’extension avec le modèle de programmation Python v2. Vérifiez votre version à l’aide de
func --version
.Visual Studio Code doit être installé sur l’une des plateformes prises en charge.
Créer l’extension de Worker Python
L’extension que vous créez signale le temps écoulé d’un appel de déclencheur HTTP dans les journaux de la console et dans le corps de la réponse HTTP.
Structure de dossiers
Le dossier de votre extension de projet doit suivre la structure suivante :
<python_worker_extension_root>/
| - .venv/
| - python_worker_extension_timer/
| | - __init__.py
| - setup.py
| - readme.md
Dossier\fichier | Description |
---|---|
.venv/ | (Facultatif) Contient un environnement virtuel Python utilisé pour le développement local. |
python_worker_extension/ | Contient le code source de l’extension de Worker Python. Ce dossier contient le module Python principal à publier dans PyPI. |
setup.py | Contient les métadonnées du package d’extension de Worker Python. |
readme.md | Contient l’instruction et l’utilisation de votre extension. Ce contenu est affiché comme descriptif dans la page d’accueil de votre projet PyPI. |
Configurer les métadonnées du projet
Tout d’abord, vous devez créer setup.py
, qui fournit des informations essentielles sur votre package. Pour vérifier que votre extension est distribuée et intégrée correctement dans les applications de fonction de votre client, vérifiez que 'azure-functions >= 1.7.0, < 2.0.0'
figure dans la section install_requires
.
Dans le modèle suivant, vous devez modifier les champs author
, author_email
, install_requires
, license
, packages
et url
en fonction des besoins.
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,
)
Ensuite, vous implémentez votre code d’extension dans l’étendue du niveau application.
Implémenter l’extension de minuterie
Ajoutez le code suivant dans python_worker_extension_timer/__init__.py
pour implémenter l’extension au niveau de l’application :
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()
Ce code hérite de AppExtensionBase, afin que l’extension s’applique à chaque fonction de l’application. Vous pouvez également implémenter l’extension sur une étendue au niveau fonction en héritant de FuncExtensionBase.
La méthode init
est une méthode de classe appelée par le Worker lors de l’importation de la classe d’extension. Vous pouvez effectuer des actions d’initialisation ici pour l’extension. Dans ce cas, un mappage de hachage est initialisé pour l’enregistrement de l’heure de début d’appel de chaque fonction.
La méthode configure
est destinée aux clients. Dans votre fichier readme, vous pouvez indiquer à vos clients le moment où ils doivent appeler Extension.configure()
. Ce fichier doit également documenter les fonctionnalités de l’extension, la configuration possible et l’utilisation de votre extension. Dans cet exemple, les clients peuvent choisir si le temps écoulé est signalé dans HttpResponse
.
La méthode pre_invocation_app_level
est appelée par le Worker Python avant l’exécution de la fonction. Elle fournit des informations sur la fonction, telles que les arguments et le contexte de la fonction. Dans cet exemple, l’extension journalise un message et enregistre l’heure de début d’un appel en fonction de son invocation_id.
De même, post_invocation_app_level
est appelé après l’exécution de la fonction. Cet exemple calcule le temps écoulé en fonction de l’heure de début et de l’heure actuelle. La valeur de retour de la réponse HTTP est également remplacée.
Créer un fichier README.md
Créez un fichier README.md à la racine de votre projet d’extension. Ce fichier contient les instructions et le guide d’utilisation de votre extension. Ce contenu du fichier README.md s’affiche en tant que description dans la page d’accueil de votre projet 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.
Utiliser votre extension localement
À présent que vous avez créé une extension, vous pouvez l’utiliser dans un projet d’application pour vérifier qu’elle fonctionne comme prévu.
Créer une fonction de déclencheur HTTP
Créez un dossier pour votre projet d’application et accédez-y.
À partir de l’interpréteur de commandes approprié, tel que Bash, exécutez la commande suivante pour initialiser le projet :
func init --python
Utilisez la commande suivante pour créer une nouvelle fonction de déclencheur HTTP qui autorise l’accès anonyme :
func new -t HttpTrigger -n HttpTrigger -a anonymous
Activer un environnement virtuel
Créez un environnement virtuel Python basé sur le système d’exploitation comme suit :
Activez l’environnement virtuel Python selon le système d’exploitation comme suit :
Configurer l’extension
Installez les packages distants de votre projet d’application de fonction à l’aide de la commande suivante :
pip install -r requirements.txt
Installez l’extension à partir de votre chemin de fichier local, en mode modifiable comme suit :
pip install -e <PYTHON_WORKER_EXTENSION_ROOT>
Dans cet exemple, remplacez
<PYTHON_WORKER_EXTENSION_ROOT>
par l’emplacement du fichier racine de votre projet d’extension.Lorsqu’un client utilise votre extension, il ajoute à la place l’emplacement de votre package d’extension au fichier requirements.txt, comme dans les exemples suivants :
Ouvrez le fichier de projet local.settings.json et ajoutez le champ suivant à
Values
:"PYTHON_ENABLE_WORKER_EXTENSIONS": "1"
Lors de l’exécution dans Azure, vous ajoutez à la place
PYTHON_ENABLE_WORKER_EXTENSIONS=1
aux paramètres de l’application dans l’application de fonction.Ajoutez les deux lignes suivantes avant la fonction
main
dans le fichier __init.py__ pour le modèle de programmation v1, ou dans le fichier function_app.py pour le modèle de programmation v2 :from python_worker_extension_timer import TimerExtension TimerExtension.configure(append_to_http_response=True)
Ce code importe le module
TimerExtension
et définit la valeur de configurationappend_to_http_response
.
Vérifier l’extension
À partir du dossier racine de votre projet d’application, démarrez l’hôte de la fonction à l’aide de
func host start --verbose
. Vous devez voir le point de terminaison local de votre fonction dans la sortie, sous la formehttps://localhost:7071/api/HttpTrigger
.Dans le navigateur, envoyez une requête GET à
https://localhost:7071/api/HttpTrigger
. Vous devez voir une réponse semblable à la suivante, avec les données TimeElapsed de la requête ajoutée.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)
Publier votre extension
Une fois que vous avez créé et vérifié votre extension, vous devez encore effectuer ces tâches de publication restantes :
- Choisir une licence.
- Créer un fichier readme.md et d’autres documentations.
- Publier la bibliothèque d’extensions dans un registre de packages Python ou un système de contrôle de version (VCS).
Pour publier votre extension sur PyPI :
Exécutez la commande suivante pour installer
twine
etwheel
dans votre environnement Python par défaut ou dans un environnement virtuel :pip install twine wheel
Supprimez l’ancien dossier
dist/
de votre référentiel d’extensions.Exécutez la commande suivante pour générer un nouveau package à l’intérieur de
dist/
:python setup.py sdist bdist_wheel
Exécutez la commande suivante pour charger le package sur PyPI :
twine upload dist/*
Vous devrez peut-être fournir les informations d’identification de votre compte PyPI lors du chargement. Vous pouvez également tester le chargement de votre package avec
twine upload -r testpypi dist/*
. Pour plus d’informations, consultez la documentation Twine.
Après ces étapes, les clients peuvent utiliser votre extension en incluant le nom de votre package dans leur fichier requirements.txt.
Pour plus d’informations, consultez le tutoriel officiel Python sur l’empaquetage.
Exemples
Vous pouvez afficher l’exemple du projet d’extension terminé à partir de cet article dans l’exemple de dépôt python_worker_extension_timer.
L’intégration de OpenCensus est un projet open source qui utilise l’interface d’extension pour intégrer le suivi de télémétrie dans les applications Python sur Azure Functions. Consultez le dépôt opencensus-python-extensions-azure pour vérifier l’implémentation de cette extension de Worker Python.
Étapes suivantes
Pour plus d’informations sur le développement Python Azure Functions, consultez les ressources suivantes :