Delen via


Python-werkrolextensies ontwikkelen voor Azure Functions

Opmerking

Vanaf Python 3.13 worden python-werkrolextensies niet meer ondersteund.

Met Azure Functions kunt u aangepast gedrag integreren als onderdeel van de uitvoering van de Python-functie. Met deze functie kunt u bedrijfslogica maken die klanten eenvoudig kunnen gebruiken in hun eigen functie-apps. Werkrolextensies worden ondersteund in zowel de v1- als v2 Python-programmeermodellen.

In deze handleiding leer je hoe je:

  • Maak een Python-werkuitbreiding op toepassingsniveau voor Azure Functions.
  • Gebruik uw extensie in een app zoals uw klanten dat doen.
  • Bereid en publiceer de extensie voor gebruik.

Vereiste voorwaarden

Voordat u begint, moet u aan deze vereisten voldoen:

De Python Worker-extensie maken

De extensie die u maakt, rapporteert de verstreken tijd van een HTTP-triggeraanroep in de consolelogboeken en in de hoofdtekst van het HTTP-antwoord.

Mapstructuur

De map voor uw extensieproject moet eruitzien als de volgende structuur:

<python_worker_extension_root>/
 | - .venv/
 | - python_worker_extension_timer/
 | | - __init__.py
 | - setup.py
 | - readme.md
Map/bestand Description
.venv/ (Optioneel) Bevat een virtuele Python-omgeving die wordt gebruikt voor lokale ontwikkeling.
python_worker_extension/ Bevat de broncode van de Python-werkrolextensie. Deze map bevat de belangrijkste Python-module die moet worden gepubliceerd in PyPI.
setup.py Bevat de metagegevens van het Python Worker-extensiepakket.
readme.md Bevat de instructies en het gebruik van uw extensie. Deze inhoud wordt weergegeven als de beschrijving op de startpagina in uw PyPI-project.

Projectmetagegevens configureren

Eerst maakt u setup.py, dat essentiële informatie over uw pakket biedt. Om ervoor te zorgen dat uw extensie correct is gedistribueerd en geïntegreerd in de functie-apps van uw klant, controleert u of deze 'azure-functions >= 1.7.0, < 2.0.0' zich in de install_requires sectie bevindt.

In de volgende sjabloon moet u indien nodig de velden , , author, author_emailinstall_requireslicenseen packages velden wijzigen.url

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,
)

Vervolgens implementeert u uw extensiecode binnen de toepassingsniveau-scope.

De timerextensie implementeren

Voeg de volgende code toe python_worker_extension_timer/__init__.py om de extensie op toepassingsniveau te implementeren:

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()

Deze code neemt over van AppExtensionBase , zodat de extensie van toepassing is op elke functie in de app. U kunt de extensie ook op een functieniveaubereik implementeren door deze af te leiden van FuncExtensionBase.

De init-methode is een klassemethode die door de worker wordt aangeroepen wanneer de extensie class wordt geïmporteerd. U kunt hier initialisatieacties uitvoeren voor de extensie. In dit geval wordt een hashmap geïnitialiseerd om de starttijd van de aanroep voor elke functie vast te leggen.

De configure methode is klantgericht. In uw leesmij-bestand kunt u uw klanten aangeven wanneer zij contact moeten opnemen Extension.configure(). Het leesmij-bestand moet de uitbreidingsmogelijkheden, de mogelijke configuratie en het gebruik van uw extensie ook documenteren. In dit voorbeeld kunnen klanten kiezen of de verstreken tijd wordt gerapporteerd in de HttpResponse.

De pre_invocation_app_level methode wordt aangeroepen door de Python-worker voordat de functie uitgevoerd wordt. Het bevat de informatie van de functie, zoals functiecontext en argumenten. In dit voorbeeld registreert de extensie een bericht en registreert de begintijd van een aanroep op basis van de invocation_id.

Op dezelfde manier wordt de post_invocation_app_level aangeroepen na de uitvoering van de functie. In dit voorbeeld wordt de verstreken tijd berekend op basis van de begintijd en de huidige tijd. Ook wordt de retourwaarde van het HTTP-antwoord overschreven.

Een readme.md maken

Maak een readme.md-bestand in de hoofdmap van het extensieproject. Dit bestand bevat de instructies en het gebruik van uw extensie. De readme.md inhoud wordt weergegeven als de beschrijving op de startpagina van uw PyPI-project.

# 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.

Je extensie lokaal gebruiken

Nu u een extensie hebt gemaakt, kunt u deze in een app-project gebruiken om te controleren of het werkt zoals bedoeld.

Een HTTP-triggerfunctie maken

  1. Maak een nieuwe map voor uw app-project en navigeer ernaartoe.

  2. Voer vanuit de juiste shell, zoals Bash, de volgende opdracht uit om het project te initialiseren:

    func init --python
    
  3. Gebruik de volgende opdracht om een nieuwe HTTP-triggerfunctie te maken die anonieme toegang toestaat:

    func new -t HttpTrigger -n HttpTrigger -a anonymous
    

Een virtuele omgeving activeren

  1. Maak als volgt een virtuele Python-omgeving op basis van het besturingssysteem:

    python3 -m venv .venv
    
  2. Activeer de virtuele Python-omgeving op basis van het besturingssysteem als volgt:

    source .venv/bin/activate
    

De extensie configureren

  1. Installeer externe pakketten voor uw functie-app-project met behulp van de volgende opdracht:

    pip install -r requirements.txt
    
  2. Installeer de extensie vanuit uw lokale bestandspad in de bewerkbare modus als volgt:

    pip install -e <PYTHON_WORKER_EXTENSION_ROOT>
    

    Vervang in dit voorbeeld door <PYTHON_WORKER_EXTENSION_ROOT> de locatie van het hoofdbestand van uw extensieproject.

    Wanneer een klant uw extensie gebruikt, voegt deze in plaats daarvan de locatie van het extensiepakket toe aan het requirements.txt-bestand, zoals in de volgende voorbeelden:

    # requirements.txt
    python_worker_extension_timer==1.0.0
    
  3. Open het local.settings.json projectbestand en voeg het volgende veld toe aan Values:

    "PYTHON_ENABLE_WORKER_EXTENSIONS": "1" 
    

    Wanneer u in Azure werkt, voegt u in plaats daarvan toe PYTHON_ENABLE_WORKER_EXTENSIONS=1 aan de app-instellingen in de functie-app.

  4. Voeg de volgende twee regels toe vóór de main functie in het bestand __init.py__ voor het v1-programmeermodel of in het function_app.py-bestand voor het v2-programmeermodel:

    from python_worker_extension_timer import TimerExtension
    TimerExtension.configure(append_to_http_response=True)
    

    Met deze code wordt de TimerExtension module geïmporteerd en wordt de append_to_http_response configuratiewaarde ingesteld.

De extensie controleren

  1. Start vanuit de hoofdmap van uw app-project de functiehost met behulp van func host start --verbose. U zou het lokale eindpunt van uw functie in de uitvoer als https://localhost:7071/api/HttpTrigger moeten zien.

  2. Verzend in de browser een GET-aanvraag naar https://localhost:7071/api/HttpTrigger. U zou een antwoord moeten zien zoals het volgende, waarbij de TimeElapsed-gegevens voor dit verzoek zijn toegevoegd.

    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)
    

Uw extensie publiceren

Nadat u de extensie hebt gemaakt en geverifieerd, moet u nog steeds deze resterende publicatietaken uitvoeren:

  • Kies een licentie.
  • Maak een readme.md en andere documentatie.
  • Publiceer de extensiebibliotheek naar een Python-pakketregister of een versiebeheersysteem (VCS).

Uw extensie publiceren naar PyPI:

  1. Voer het volgende commando uit om twine en wheel in uw standaard Python-omgeving of een virtuele omgeving te installeren.

    pip install twine wheel
    
  2. Verwijder de oude dist/ map uit de extensieopslagplaats.

  3. Voer de volgende opdracht uit om een nieuw pakket binnen dist/te genereren:

    python setup.py sdist bdist_wheel
    
  4. Voer de volgende opdracht uit om het pakket te uploaden naar PyPI:

    twine upload dist/*
    

    Mogelijk moet u tijdens het uploaden uw PyPI-accountreferenties opgeven. U kunt het uploaden van uw pakket ook testen met twine upload -r testpypi dist/*. Zie de Documentatie van Twine voor meer informatie.

Na deze stappen kunnen klanten uw extensie gebruiken door uw pakketnaam op te nemen in hun requirements.txt.

Voor meer informatie, zie de officiële Python-verpakkingshandleiding.

Voorbeelden

  • U kunt het voltooide voorbeelduitbreidingsproject uit dit artikel bekijken in de python_worker_extension_timer voorbeeldopslagplaats.

  • OpenCensus-integratie is een opensource-project dat gebruikmaakt van de extensie-interface voor het integreren van telemetrietracering in Python-apps van Azure Functions. Zie de opslagplaats opencensus-python-extensions-azure om de implementatie van deze Python-werkrolextensie te controleren.

Volgende stappen

Zie de volgende resources voor meer informatie over het ontwikkelen van Azure Functions Python: