Mengembangkan ekstensi pekerja Python untuk Azure Functions

Azure Functions memungkinkan Anda mengintegrasikan perilaku kustom sebagai bagian dari eksekusi fungsi Python. Fitur ini memungkinkan Anda membuat logika bisnis yang dapat digunakan pelanggan dengan mudah di aplikasi fungsinya sendiri. Untuk mempelajari selengkapnya, lihat referensi pengembang Python. Ekstensi pekerja didukung dalam model pemrograman Python v1 dan v2.

Dalam tutorial ini, Anda akan mempelajari cara:

  • Buat ekstensi pekerja Python tingkat aplikasi untuk Azure Functions.
  • Konsumsi ekstensi Anda di aplikasi seperti yang dilakukan oleh para pelanggan.
  • Paketkan dan terbitkan ekstensi untuk konsumsi.

Prasyarat

Sebelum mulai, Anda harus memenuhi persyaratan ini:

Membuat ekstensi Python Worker

Ekstensi yang Anda buat melaporkan waktu yang berlalu pada pemanggilan pemicu HTTP di log konsol dan di badan respons HTTP.

Struktur folder

Folder untuk proyek ekstensi Anda harus seperti struktur berikut:

<python_worker_extension_root>/
 | - .venv/
 | - python_worker_extension_timer/
 | | - __init__.py
 | - setup.py
 | - readme.md
Folder/file Deskripsi
.venv/ (Opsional) Berisi lingkungan virtual Python yang digunakan oleh pengembangan lokal.
python_worker_extension/ Berisi kode sumber daya ekstensi pekerja Python. Folder ini berisi modul Python utama yang akan diterbitkan ke dalam PyPI.
setup.py Berisi metadata paket ekstensi pekerja Python.
readme.md Berisi instruksi dan penggunaan ekstensi Anda. Konten ini ditampilkan sebagai deskripsi di halaman selamat datang dalam proyek PyPI Anda.

Mengonfigurasi metadata proyek

Pertama Anda membuat setup.py, yang memberikan informasi penting tentang paket Anda. Untuk memastikan bahwa ekstensi Anda didistribusikan dan diintegrasikan ke dalam aplikasi fungsi pelanggan Anda dengan benar, konfirmasikan bahwa 'azure-functions >= 1.7.0, < 2.0.0' ada di bagian install_requires tersebut.

Dalam templat berikut, Anda harus mengubah bidang author, author_email, install_requires, license, packages, dan url sesuai kebutuhan.

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

Selanjutnya, Anda akan menerapkan kode ekstensi dalam lingkup tingkat aplikasi.

Menerapkan ekstensi timer

Tambahkan kode berikut dalam python_worker_extension_timer/__init__.py untuk mengimplementasikan ekstensi tingkat aplikasi:

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

Kode ini mewarisi dari AppExtensionBase sehingga ekstensi berlaku untuk setiap fungsi di aplikasi. Anda juga dapat menerapkan ekstensi pada lingkup tingkat fungsi dengan mewarisi dari FuncExtensionBase.

Metode init adalah metode kelas yang disebut oleh pekerja ketika kelas ekstensi diimpor. Anda dapat melakukan tindakan inisialisasi di sini untuk ekstensi. Dalam hal ini, peta hash diinisialisasi untuk merekam waktu mulai pemanggilan bagi setiap fungsi.

Metode configure ini berhadapan dengan pelanggan. Dalam file readme, Anda dapat memberi tahu pelanggan Anda apakah mereka perlu menelepon Extension.configure(). Readme juga harus mendokumentasikan kemampuan ekstensi, konfigurasi yang mungkin, dan penggunaan ekstensi Anda. Dalam contoh ini, pelanggan dapat memilih apakah waktu yang berlalu dilaporkan dalam HttpResponse.

Metode pre_invocation_app_level ini disebut oleh pekerja Python sebelum fungsi dijalankan. Ini memberikan informasi dari fungsi, seperti konteks fungsi dan argumen. Dalam contoh ini, ekstensi mencatat pesan dan merekam waktu mulai pemanggilan berdasarkan invocation_id.

Demikian pula, post_invocation_app_level disebut setelah eksekusi fungsi. Contoh ini menghitung waktu yang berlalu berdasarkan waktu mulai dan waktu saat ini. Contoh ini juga menimpa nilai pengembalian respons HTTP.

Membuat readme.md

Buat file readme.md di akar proyek ekstensi Anda. File ini berisi instruksi dan penggunaan ekstensi Anda. Konten readme.md ditampilkan sebagai deskripsi di halaman beranda di proyek PyPI Anda.

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

Konsumsi ekstensi Anda secara lokal

Setelah membuat ekstensi, Anda dapat menggunakannya dalam project aplikasi untuk memverifikasi bahwa ekstensi tersebut berfungsi sebagaimana mestinya.

Membuat fungsi pemicu HTTP

  1. Buat folder baru untuk proyek aplikasi Anda dan navigasikan ke folder tersebut.

  2. Dari shell yang sesuai, seperti Bash, jalankan perintah berikut untuk menginisialisasi proyek:

    func init --python
    
  3. Gunakan perintah berikut untuk membuat fungsi pemicu HTTP baru yang memungkinkan akses anonim:

    func new -t HttpTrigger -n HttpTrigger -a anonymous
    

Aktifkan lingkungan virtual

  1. Buat lingkungan virtual Python, berdasarkan OS sebagai berikut:

    python3 -m venv .venv
    
  2. Aktifkan lingkungan virtual Python, berdasarkan OS sebagai berikut:

    source .venv/bin/activate
    

Mengonfigurasi ekstensi

  1. Instal paket jarak jauh untuk project aplikasi fungsi Anda dengan menggunakan perintah berikut:

    pip install -r requirements.txt
    
  2. Instal ekstensi dari jalur file lokal Anda, dalam mode yang dapat diedit sebagai berikut:

    pip install -e <PYTHON_WORKER_EXTENSION_ROOT>
    

    Dalam contoh ini, ganti <PYTHON_WORKER_EXTENSION_ROOT> dengan lokasi file akar proyek ekstensi Anda.

    Saat pelanggan menggunakan ekstensi Anda, mereka justru akan menambahkan lokasi paket ekstensi Anda ke file requirements.txt, seperti dalam contoh berikut:

    # requirements.txt
    python_worker_extension_timer==1.0.0
    
  3. Buka file proyek local.settings.json dan tambahkan bidang berikut ke Values:

    "PYTHON_ENABLE_WORKER_EXTENSIONS": "1" 
    

    Saat berjalan di Azure, Anda justru menambahkan PYTHON_ENABLE_WORKER_EXTENSIONS=1 ke pengaturan aplikasi di aplikasi fungsi.

  4. Tambahkan dua baris berikut sebelum main fungsi dalam file __init.py__ untuk model pemrograman v1, atau dalam file function_app.py untuk model pemrograman v2:

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

    Kode ini mengimpor TimerExtension modul dan menetapkan append_to_http_response nilai konfigurasi.

Verifikasi ekstensi

  1. Dari folder akar proyek aplikasi Anda, mulai host fungsi dengan menggunakan func host start --verbose. Anda akan melihat titik akhir lokal fungsi Anda dalam output sebagai https://localhost:7071/api/HttpTrigger.

  2. Di browser, kirim permintaan GET ke https://localhost:7071/api/HttpTrigger. Anda akan melihat respons seperti berikut ini, dengan data TimeElapsed untuk tambahan permintaan.

    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)
    

Mempublikasikan ekstensi Anda

Setelah membuat dan memverifikasi ekstensi, Anda masih perlu menyelesaikan tugas penerbitan yang tersisa ini:

  • Pilih lisensi.
  • Membuat readme.md dan dokumentasi lainnya.
  • Publikasikan pustaka ekstensi ke registri paket Python atau sistem kontrol versi (VCS).

Untuk mempublikasikan ekstensi Anda ke PyPI:

  1. Jalankan perintah berikut untuk menginstal twine dan wheel di lingkungan Python default Anda atau lingkungan virtual:

    pip install twine wheel
    
  2. Hapus folder lama dist/ dari repositori ekstensi Anda.

  3. Jalankan perintah berikut untuk menghasilkan paket baru di dalam dist/:

    python setup.py sdist bdist_wheel
    
  4. Jalankan perintah berikut untuk mengunggah paket ke PyPI:

    twine upload dist/*
    

    Anda mungkin perlu memberikan kredensial akun PyPI Anda selama pengunggahan. Anda juga dapat menguji unggahan paket Anda dengan twine upload -r testpypi dist/*. Untuk informasi selengkapnya, lihat dokumentasi Twine.

Setelah langkah-langkah ini, pelanggan dapat menggunakan ekstensi Anda dengan menyertakan nama paket Anda di requirements.txt.

Untuk informasi selengkapnya, lihat tutorial pengemasan Python resmi.

Contoh

  • Anda dapat melihat proyek ekstensi sampel yang telah selesai dari artikel ini dalam penyimpanan sampel python_worker_extension_timer.

  • Integrasi OpenCensus adalah proyek sumber terbuka yang menggunakan antarmuka ekstensi untuk mengintegrasikan pelacakan telemetri di aplikasi Azure Functions Python. Lihat repositori opencensus-python-extensions-azure untuk meninjau implementasi ekstensi pekerja Python ini.

Langkah berikutnya

Untuk informasi selengkapnya tentang pengembangan Azure Functions Phyton, lihat referensi berikut ini: