Azure Functions – na dzisiaj ślepa uliczka dla API

Table of contents
- Azure Functions – obietnica serverless, rzeczywistość dla API
- Dwa modele: in-process vs out-of-process
- Problemy modelu out-of-process w budowie API
- Model in-process – umiera, ale był bardziej wygodny
- Flex Consumption – odpowiedź na problem cold startów w Azure Functions
- Azure App Service – stary dobry koń roboczy
- Podsumowanie: Nie każde rozwiązanie to API

Azure Functions – obietnica serverless, rzeczywistość dla API
Azure Functions obiecywały wiele: skalowalność, niski koszt, zero zarządzania infrastrukturą. W teorii to idealne miejsce na wystawienie prostego API, zwłaszcza przy nieregularnym ruchu. W praktyce – funkcje nie są kompletnym frameworkiem webowym do budowy interfejsów HTTP. Tworzenie API w tym modelu często kończy się rozczarowaniem. Szczególnie teraz, gdy Microsoft porzuca stary model (in-process), a nowy (out-of-process) wprowadza poważne ograniczenia.
Dwa modele: in-process vs out-of-process
Usługa Azure Functions zadebiutowała na platformie Azure w 2016 roku jako rozwiązanie serverless, które pozwala uruchamiać małe, niezależne funkcje reagujące na zdarzenia – takie jak żądania HTTP, wiadomości z kolejki czy zdarzenia czasowe – bez potrzeby zarządzania infrastrukturą. Początkowo funkcje działały wyłącznie w modelu in-process, czyli były uruchamiane w tym samym procesie, co host Azure Functions. Pozwalało to na korzystanie z naturalnego dla programistów zestawu narzędzi ASP.NET przy budowie API – takiego samego, jak w aplikacjach OnPremises, kontenerach Docker czy Azure App Service.
Z czasem jednak ten model zaczął ujawniać swoje ograniczenia. Współdzielenie procesu z hostem oznaczało brak izolacji środowisk, trudności w aktualizacji wersji .NET, konflikty zależności oraz ograniczoną możliwość niezależnego rozwoju i testowania. Problemem była też niższa niezawodność i większe ryzyko błędów przy uruchamianiu bardziej złożonych projektów.
Aby zaadresować te wyzwania, Microsoft wprowadził w 2020 roku model out-of-process (znany również jako isolated worker). Funkcje działają tu w osobnym procesie .NET, który komunikuje się z hostem za pomocą RPC. Taka separacja pozwala używać dowolnych wersji środowiska .NET niezależnie od platformy Azure Functions i unikać konfliktów wersji.
Model isolated eliminuje wiele ograniczeń technicznych modelu in-process, ale jednocześnie rezygnuje z kilku kluczowych cech. Microsoft zdecydował, że to właśnie model out-of-process będzie jedynym wspieranym w przyszłości. Wsparcie dla Azure Functions in-process zakończy się w listopadzie 2026 roku.
Problemy modelu out-of-process w budowie API
Model out-of-process rozwiązuje pewne problemy techniczne starszego podejścia, ale w kontekście budowy API wprowadza wiele ograniczeń. Trudno je zaakceptować przy pracy nad rzeczywistymi usługami HTTP. Poniżej przedstawiam najważniejsze z nich:
Brak wsparcia dla ASP.NET
Nie można użyć UseMiddleware(), nie ma dostępu do IApplicationBuilder. Oznacza to, że nie zbuduje się automatycznie pełnego pipeline’u z autoryzacją, walidacją modeli, filtrowaniem błędów. Wszystko trzeba implementować inaczej i bardziej ręcznie. W praktyce oznacza to więcej kodu do utrzymania oraz utratę możliwości szybkiego zmianu sposobu hostowania API - gdy zdecydujesz się budowac w Isolated Model, migracja to innego środowiska będzie kosztowna.
Brak możliwości użycia najlepszych narzędzi do generowania dokumentacji API
W Azure Functions Isolated model, nie da się po prostu dodać Swashbuckle/Swagger do generowania dokumentacji jak w Web API. Potrzebna jest osobna biblioteka -Microsoft.Azure.Functions.Worker.Extensions.OpenAPI. Niestety na dzisiaj ma ona ograniczenia. Nie wspiera wielu cech ASP.NET, na przykład generowania dokumentacji dla klas powiązanych dziedziczeniem należących do kontraktu. Dodatkowo konfiguracja biblioteki jest mniej intuicyjna, a dokumentacja bywa niejasna. DX (Developer Experience) wyraźnie się pogarsza.
Cold start i niestabilna wydajność
Model out-of-process wymaga uruchomienia osobnego procesu. W planie konsumpcyjnym może to oznaczać kilkadziesiąt sekund czekania na odpowiedź po dłuższej przerwie. Co gorsza, każdy endpoint HTTP traktowany jest niezależnie – jeśli Twoje API składa się z wielu funkcji, to każda z nich ma własny cold start. W modelu in-process wystarczyło rozgrzać jeden endpoint (np. /health), by uruchomić cały proces hosta i tym samym „wybudzić” wszystkie punkty dostępowe na raz. W modelu isolated to już nie działa. Cold starty są bardziej dotkliwe i trudniejsze do obejścia. W mojej ocenie to show stopper dla większości przypadków tworzenia publicznego API.
Model in-process – umiera, ale był bardziej wygodny
Mimo swoich ograniczeń, model in-process był po prostu praktyczny dla małych API. Działał jak okrojony ASP.NET Web API – wspierał kontrolery, middleware, znane mechanizmy DI, a wiele gotowych narzędzi działało od ręki. Teraz Microsoft oficjalnie każe go porzucić. Od .NET 8 wspierany jest wyłącznie isolated worker. Jeśli korzystałeś wcześniej z in-process, będziesz musiał zaplanować migrację. Jeśli dopiero zaczynasz – warto rozważyć inne podejście do hostowania API, na przykład Azure App Service.
Flex Consumption – odpowiedź na problem cold startów w Azure Functions
Flex Consumption Plan pojawił się w Azure Functions w 2024 roku jako odpowiedź na problem cold startów. Ten model łączy zalety serverless podstawowego planu Consumption z utrzymywaniem funkcji w stanie „ciepłym” podobnie jak w planie Premium. Dzięki temu w API o nieregularnym ruchu pierwsze żądania trafiają do w pełni gotowych instancji, a ryzyko cold startu jest minimalne. Przy skalowaniu Azure korzysta z puli wstępnie przygotowanych instancji, dzięki czemu kolejne instancje uruchamiają się znacznie szybciej niż w klasycznym Consumption.
Niestety korzystanie z opcji Always Ready Instances oznacza stałe koszty – tu nie ma już darmowego miliona requestów miesięcznie, a płaci się cały czas, podobnie jak w App Service. Dodatkowo usługa nie eliminuje pozostałych ograniczeń modelu isolated.
Azure App Service – stary dobry koń roboczy
Jeśli chcesz wystawić produkcyjne REST API, nawet małe, to Azure App Service z Minimal API lub Web API moim zdaniem będzie lepszym wyborem.
Dostajesz:
pełne wsparcie powszechnie znanego przez deweloperów środowiska ASP.NET,
działające Swashbuckle w 3 linijki,
middleware, DI, filtry, walidację modeli,
przewidywalne czasy odpowiedzi i brak cold startów,
bardzo dobre lokalne testowanie – zwłaszcza jeśli używasz kontenerów
możliwość prostrzej migracji rozwiązania w przyszłości na inne platformy
Azure App Service daje elastyczność. Możesz uruchomić API jako zwykłą aplikację lub jako kontener – zarówno na Windowsie, jak i Linuksie.
Choć nie ma planu płatności „pay-as-you-go”, to już dziś można mieć stale działające API produkcyjne na Linuksie za ok. 45 zł miesięcznie.
Jeśli więc chcesz hostować małe API bez obaw o wydajność i przewidywalność działania – moim zdaniem Azure App Service wygrywa jakością i ergonomią z Azure Functions Isolated Model.
Jak używam Azure App Service
Sam wykorzystuję Azure App Service do hostowania mojego pet projektu - aplikacji z żartami Jokes Portal. Jest to aplikajca mobilna, która wykorzystuje Azure App Service. Działa 24/7, obsługuje realnych użytkowników i potrzebuje stabilnego API bez cold startów. Usługa sprawdza się tu znakomicie.
Podsumowanie: Nie każde rozwiązanie to API
W tym artykule skupiłem się wyłącznie na przypadku budowy REST API. Nie twierdzę, że Azure Functions są złe – wręcz przeciwnie. Model isolated to świetne narzędzie do budowy systemów event driven w chmurze Azure. Funkcje wspierają integracje z niemal wszystkimi usługami Azure out-of-the-box i doskonale sprawdzają się w scenariuszach asynchronicznych oraz transakcjach rozproszonych (Durable Functions).
Ze względu na opisane wyżej ograniczenia uważam, że Azure Functions w modelu isolated nie nadają się dziś do budowy synchronicznych REST API. W takich przypadkach warto postawić na Azure App Service. To może nie jest modne, ale po prostu działa.
Subscribe to my newsletter
Read articles from Beniamin Lenarcik directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Beniamin Lenarcik
Beniamin Lenarcik
.NET Developer | I build applications from concept to production. On my blog, I share practical examples (.NET “by example”) and thoughts on software architecture and bridging technology with business.