Python-werkrolextensies ontwikkelen voor Azure Functions

met Azure Functions kunt u aangepast gedrag integreren als onderdeel van de uitvoering van Python-functies. Met deze functie kunt u bedrijfslogica maken die klanten eenvoudig kunnen gebruiken in hun eigen functie-apps. Zie de naslaginformatie voor Python-ontwikkelaars voor meer informatie. Werkrolextensies worden ondersteund in zowel het Python-programmeermodel v1 als het v2-programmeermodel.

In deze zelfstudie leert u het volgende:

  • Maak een Python-werkrolextensie op toepassingsniveau voor Azure Functions.
  • Gebruik uw extensie in een app zoals uw klanten dat doen.
  • Een extensie verpakken en publiceren voor verbruik.

Vereisten

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 er ongeveer als volgt uitzien:

<python_worker_extension_root>/
 | - .venv/
 | - python_worker_extension_timer/
 | | - __init__.py
 | - setup.py
 | - readme.md
Map/bestand Beschrijving
.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-werkuitbreidingspakket.
readme.md Bevat de instructies en het gebruik van uw extensie. Deze inhoud wordt weergegeven als de beschrijving op de startpagina van uw PyPI-project.

Projectmetagegevens configureren

Eerst maakt setup.pyu , dat essentiële informatie over uw pakket bevat. Als u ervoor wilt zorgen dat uw extensie correct wordt gedistribueerd en geïntegreerd in de functie-apps van uw klant, controleert u of dit 'azure-functions >= 1.7.0, < 2.0.0' in de install_requires sectie staat.

In de volgende sjabloon moet u de velden , author_email, install_requires, licensepackages, en url indien nodig wijzigenauthor.

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 de extensiecode in het bereik op toepassingsniveau.

De timerextensie implementeren

Voeg de volgende code toe in 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 wordt overgenomen van AppExtensionBase , zodat de extensie van toepassing is op elke functie in de app. U kunt de extensie ook implementeren op een bereik op functieniveau door deze over te nemen van FuncExtensionBase.

De init methode is een klassemethode die wordt aangeroepen door de werkrol wanneer de extensieklasse wordt geïmporteerd. U kunt hier initialisatieacties uitvoeren voor de extensie. In dit geval wordt een hash-toewijzing geïnitialiseerd voor het vastleggen van de begintijd van de aanroep voor elke functie.

De configure methode is klantgericht. In uw leesmij-bestand kunt u uw klanten laten weten wanneer ze moeten aanroepen Extension.configure(). De leesmij moet ook de uitbreidingsmogelijkheden, mogelijke configuratie en het gebruik van uw extensie documenteert. 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-werkrol voordat de functie wordt uitgevoerd. Het biedt 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 aangeroepen na de post_invocation_app_level 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 uw 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.

Uw extensie lokaal gebruiken

Nu u een extensie hebt gemaakt, kunt u deze gebruiken in een app-project om te controleren of deze 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 als volgt op basis van het besturingssysteem:

    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 als volgt vanuit uw lokale bestandspad in de bewerkbare modus:

    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 projectbestand local.settings.json en voeg het volgende veld toe aan Values:

    "PYTHON_ENABLE_WORKER_EXTENSIONS": "1" 
    

    Wanneer u in Azure uitvoert, 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 bestand function_app.py 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 ziet het lokale eindpunt van uw functie in de uitvoer als https://localhost:7071/api/HttpTrigger.

  2. Verzend in de browser een GET-aanvraag naar https://localhost:7071/api/HttpTrigger. U ziet een antwoord dat lijkt op het volgende, met de TimeElapsed-gegevens voor de aanvraag 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 uw 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 de volgende opdracht uit om en wheel te installeren twine in uw standaard Python-omgeving of een virtuele omgeving:

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

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

    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 uw PyPI-accountreferenties opgeven tijdens het uploaden. U kunt het uploaden van uw pakket ook testen met twine upload -r testpypi dist/*. Zie de Twine-documentatie voor meer informatie.

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

Zie de officiële zelfstudie voor Python-pakketten voor meer informatie.

Voorbeelden

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

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

Volgende stappen

Zie de volgende resources voor meer informatie over Azure Functions python-ontwikkeling: