Головна / Статті / Розробка локальних Azure Functions: усунення поширених проблем з функціонуванням

Розробка локальних Azure Functions: усунення поширених проблем з функціонуванням

Дізнайтеся, як Core Tools, мовні середовища виконання та Azurite повинні бути сумісними, а також отримайте практичні рішення щодо файлу local.settings.json, тригерів та помилок у налагоджуванні.

1892 слів

Припиніть боротися з емуляторами, несправними налаштуваннями та загадковими помилками — ось що справді працює

Якщо звичайна команда func start коли-небудь раптово показала вам екран, заповнений червоним текстом, без жодного попередження, ви зовсім не єдиний у цьому. Azure Functions працює чудово після розгортання в хмарі, але змусити його без проблем працювати на вашому власному ноутбуці — це те, через що багато розробників марнують ціле пополудня без жодної на те причини.

Цей посібник ігнорує відшліфовану маркетингову версію поняття „локальна розробка“ та замість цього детально розглядає справжні проблеми, причини їх виникнення та практичні рішення, засновані на труднощах, з якими регулярно стикаються розробники.

1. Чому локальна розробка Azure Functions здається складнішою, ніж мала б бути

Запуск Azure Functions на власному комп’ютері — це не просто виконання коду. Фактично ви створюєте локально цілу хмарну середовище виконання: хостинг Functions, налаштування тригерів, черги зберігання, а іноді й механізми автентифікації, причому без будь-якого впливу на сам Azure. Для цього на кожному етапі необхідно забезпечити синхронну роботу трьох окремих елементів:

  • Core Tools CLI від Microsoft, який є аналогом хостованого середовища виконання Functions, яке зазвичай надається самим Azure
  • Мову програмування та SDK, на яких написані ваші функції — чи то Node.js, Python, .NET, Java чи PowerShell
  • Azurite, невеликий емулятор, який імітує Azure Storage, щоб черги, блоки даних та таблиці функціонували без реального хмарного облікового запису

Якщо хоча б одна з цих трьох складових є неправильною версією, погано налаштованою або просто не увімкненою, ви зіткнетеся з типовими проблемами: функції, які відмовляються працювати, повідомлення „Рахунок зберігання не знайдено“ або хост, який тихо завершує роботу. Як тільки ви зрозумієте, як ці три елементи залежать один від одного, більша частина розчарувань зникне.

2. Що насправді потрібно встановити

Перш ніж торкатися коду будь-якої функції, переконайтеся, що у вас є наступне:

  • Azure Functions Core Tools — інструмент командного рядка, який запускає хост Functions на вашому комп’ютері
npm install -g azure-functions-core-tools@4 --unsafe-perm true
  • Мовний движок, сумісний з вашою цільовою версією Azure (наприклад, Node.js 18/20, Python 3.9–3.11 або .NET 8)
  • Azurite — емулятор, який імітує Azure Storage локально
npm install -g azurite
  • VS Code у поєднанні з розширенням Azure Functions — це не обов’язково, але це значно полегшує відладку та створення основи проекту

Швидка перевірка, яку варто здійснити перед подальшими діями:

func --version
node --version    # or python --version / dotnet --version

Різниця версій між Core Tools та движком вашої мови є однією з найпоширеніших причин, чому щось працює без проблем на одній машині, але не запускається на іншій.

3. Налаштування вашого першого локального Function App

Використовуйте CLI для створення абсолютно нового проекту:

func init MyFunctionApp --worker-runtime node
cd MyFunctionApp
func new --name HttpTriggerExample --template "HTTP trigger"

Після запуску ви отримаєте структуру папок із файлом host.json, файлом local.settings.json та директорією, яка містить код вашого тригеру. Файл host.json відповідає за налаштування для всього хоста, такі як поведінка журналування, пакети розширень та таймаути. Файл local.settings.json призначений лише для вашого комп’ютера, і його наявність під час першого запуску викликає достатньо плутанини, тож він потребує окремого пояснення.

4. Файл local.settings.json — що він робить та чому він спричиняє проблеми

Цей файл зберігає ваші локальні змінні середовища та рядки підключення. Його ніколи не передають у Azure; його єдина мета — локальна налаштування.

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "node"
  }
}

Два поширені помилки пояснюють більшість скарг на те, що „хост навіть не запускається“:

  1. Забування про налаштування AzureWebJobsStorage. Майже кожна категорія тригерів — Timer, Queue, Blob — потребує підключення до сховища, навіть під час локальних виконань. Використання параметра UseDevelopmentStorage=true спрямовує хост на Azurite замість реального облікового запису Azure Storage.
  2. Неправильне налаштування FUNCTIONS_WORKER_RUNTIME. Якщо цей параметр не збігається з мовою програмування, якою ви фактично працюєте (node, python, dotnet, java, powershell), хост просто не завантажуватиме ваші функції, зазвичай відображаючи нечітку інформацію про помилку замість чіткого повідомлення про неузгодженість середовища виконання.

5. Azurite: ваш емулятор локального сховища (і чому його неможливо пропустити)

Azurite замінює Azure Storage для всього, що працює локально, імітуючи черги, блоби та таблиці прямо на вашому комп’ютері. Ігнорування цього кроку є основною причиною помилок StorageException або відмов у підключенні, як тільки з’являється виклик черги чи блобу.

Запустіть його у спеціальному вікні терміналу перед тим, як запустити ваше додаток функцій:

azurite --silent --location ./azurite-data --debug ./azurite-data/debug.log

Якщо ви волієте працювати у VS Code, розширення Azurite дозволяє запустити емулятор через один запис у палітрі команд, без необхідності окремого терміналу. Яким би шляхом ви не обрали, тримайте його у робочому стані протягом усієї сесії — дуже легко забути, що він не активний, і витратити десять хвилин на пошук повідомлення „підключення відмовлено“, яке насправді означає лише те, що емулятор так і не був запущений.

6. Запуск та тестування функцій, запущених за допомогою HTTP-тригерів

Як тільки Azurite буде запущений, стартуйте вашу додаткову програму:

func start

У вашому терміналі буде вказано локальний URL кожної функції, приблизно у такому вигляді:

Http Functions:
    HttpTriggerExample: [GET,POST] http://localhost:7071/api/HttpTriggerExample

Якщо це запит типу GET, ви можете скористатися curl, Postman або браузером для його виконання:

curl "http://localhost:7071/api/HttpTriggerExample?name=Dev"

Якщо замість відповіді ви отримуєте мовчання, перевірьте наявність конфлікту портів — залишковий процес func start або інша інстанція можуть вже використовувати порт 7071. Завершення непотрібних процесів Functions (знайдіть func у Менеджері завдань або виконайте pkill -f func у macOS/Linux) зазвичай негайно вирішує цю проблему.

7. Тестування локальних тригерів, що не є HTTP (Timer, Queue, Blob, Service Bus)

Тригери HTTP — це простий випадок. Для інших потрібна додаткова підготовка:

  • Тригери таймера запускаються автоматично згідно з їхнім графіком CRON як тільки запускається хост, без додаткових вимог. Щоб протестувати їх раніше, ви можете тимчасово додати до визначення тригера "RunOnStartup": true, щоб він запустився негайно.
  • Тригери черзі потребують реального повідомлення, яке чекає в черзі, підтримуваній Azurite. Ви можете додати тестове повідомлення через Azure Storage Explorer, який взаємодіє з Azurite так само, як і з реальним обліковим записом зберігання, або за допомогою розширення зберігання Azure CLI, призначеного для вашого локального рядка підключення.
  • Тригери Blob мають тенденцію до затримок у локальному режимі, оскільки перевірка наявності нових Blob відбувається не миттєво — затримки у кілька хвилин є звичайним явищем, якщо тільки ви не користуєтесь тригерами Blob, заснованими на Event Grid. Такі тригери погано імітуються у локальному режимі, тож зазвичай краще перевіряти їх на справжньому, недорогому ресурсі Azure.
  • Тригери Service Bus та Event Hub зазвичай взагалі не можна імітувати на вашому комп’ютері. У таких випадках найкращим рішенням є використання справжнього, недорогого ресурсу Azure типу dev-tier під час локальних тестів, з посиланням на окремий рядок підключення у файлі local.settings.json.
  • Це одна з справжніх проблем у розробці функцій у локальному режимі: деякі типи тригерів просто не можна повністю відтворити у локальних умовах, а спроби розглядати їх як такі, що можна відтворити, лише марнують ваш час.

    8. Відлагоджування у VS Code

    Саме тут локальна налаштування по-справжньому починають виправдовувати себе. Після встановлення розширення Azure Functions:

    1. Відкрийте папку вашого проекту в VS Code.
    2. Розмістіть точки зупинки там, де вони потрібні, у коді-тригері.
    3. Натисніть F5 — VS Code самостійно будує проект, запускає Azurite, якщо це налаштовано, запускає хост Functions та під’єднує дебагер, усе це без необхідності виконувати додаткові кроки вручну.

    Автоматично створені файли .vscode/launch.json та tasks.json координують усе це на невидимому рівні. Якщо точки зупинки не зупиняють виконання, перевірте, чи налаштування preLaunchTask у файлі launch.json справді перебудовує ваш код перед запуском хоста — застаріла версія коду є тонкою, але поширеною причиною, чому точки зупинки, здається, ігноруються.

    9. Поширені помилки та способи їх виправлення

    Саме цей рядок створює більше плутанини у розробників, ніж будь-яка справжня проблема в самому середовищі виконання Functions. З міркувань безпеки local.settings.json навмисно не включається до пакету розгортання, що означає, що будь-які конфіденційні дані чи значення налаштувань, збережені там, не будуть автоматично передаватися разом із вашим додатком до Azure — їх потрібно додавати окремо, через портал Azure або за допомогою інструментів CLI/пайплайну.

    10. Запуск Functions локально за допомогою Docker

    Якщо ваша команда хоче, щоб локальне та продакшн-середовища були абсолютно ідентичними — або якщо вам потрібно перевірити власний Linux-контейнер — Azure Functions також пропонує варіант на основі Docker:

    func init MyFunctionApp --worker-runtime node --docker
    cd MyFunctionApp
    docker build -t my-function-app .
    docker run -p 7071:80 -it my-function-app
    

    Цей підхід створює більше навантаження порівняно з простою функцією func start, але він усуває цілу категорію проблем типу „у мене все працює“, особливо для команд, які використовують користувацькі контейнери або потребують суворої узгодженості на рівні операційної системи з тим, що працює в продакшені.

    11. Правильне керування конфіденційною інформацією та змінними середовища

    Не включайте файл local.settings.json до системи контролю версій. Він призначений для зберігання справжніх рядків підключення під час розробки, а проєкти з готовою структурою за замовчуванням виключають його з git — обов’язково перевірте свій файл .gitignore, щоб бути впевненими. Під час роботи в команді:

    • Діліться очищеною версією, наприклад local.settings.json.example, заповненою місцевими значеннями замість справжніх конфіденційних даних.
  • Як тільки ви перейдете від суто локальних тестів, для всього конфіденційного використовуйте посилання на Azure Key Vault.
  • У CI-пайплайнах передавайте конфігурацію через змінні середовища, а не додавайте справжній файл налаштувань у репозиторій.
  • 12. Найкращі практики для безперебійного локального циклу розробки

    • Запускайте Azurite перед запуском хоста Functions — порядок має значення, оскільки деякі тригери перевіряють сховище відразу після запуску.
    • Визначте точну версію Core Tools, яку використовує ваша команда, або у документації, або у скрипті налаштування. Невідповідності версій між пристроями є непомітною, але реальною перешкодою для продуктивності.
    • Запускайте func start --verbose щоразу, коли ви намагаєтесь вирішити проблему з запуском — стандартний рівень логування часто приховує справжню причину.
    • Перезавантажуйте хост щоразу, коли редагуєте host.json або local.settings.json; жоден з цих файлів не оновлюється під час гарячого завантаження.
    • Зберігайте ресурс низького рівня в Azure для типів тригерів, таких як Service Bus чи Event Grid, які неможливо повністю відтворити у локальному емуляторі.

    Заключні міркування

    Локальна розробка для Azure Functions не є фундаментально некоректною — вона просто складається з кількох компонентів, які всі мають залишатися у злагоді, і більшість посібників пропускають саме ті аспекти, які створюють справжні проблеми: правильне емулювання зберігання, неузгодженості часу виконання завдань та межі того, що може імітувати ваша локальна налаштовка. Як тільки ці три аспекти стануть зрозумілими, команда func start більше не здаватиметься випадковістю, а стане просто ще однією звичайною командою.

    Якщо існує одна звичка, яку варто запозичити з усього цього, то це така: завжди перевіряйте, чи справді працює Azurite, перш ніж починати усування будь-яких інших проблем. Одна така недбалість тихо марнує більше часу, ніж будь-яка справжня помилка у коді вашої функції.

    Пов’язана література

  • Усунення помилок обробки помилок Async/Await у продакшн-коді Node.js — Дізнайтеся про п’ять поширених помилок у обробці помилок async/await у JavaScript та Node.js, які спричиняють беззвучні збої та ситуації конкуренції, а також про конкретні способи їх усунення.
  • Усунення помилки відсутності бібліотеки libssl.so.1.1 у Prisma на Alpine Docker — Дізнайтеся, чому двигун запитів Prisma збивається у образах Docker на базі Alpine через помилку відсутності libssl, та як назавжди її вирішити.