Zarządzanie stanem w Azure Functions bez Durable Functions

Durable Functions to silnik workflow. Większość Function Appów potrzebuje tylko zmiennej, która przetrwa restart. Gdy twoim stanem jest kursor, flaga albo licznik, jeden wiersz w Table Storage zastąpi całe rozszerzenie.
Durable Functions to domyślna odpowiedź, gdy funkcja musi coś zapamiętać. To dobry silnik. To także znacznie więcej maszynerii, niż potrzebuje zapisana wartość.
Ile naprawdę kosztuje rozszerzenie
Utworzenie task huba na providerze Azure Storage dokłada do konta dwie tabele, pięć albo więcej kolejek i trzy kontenery blob.
Rachunek na tym się nie kończy:
- Polling w bezczynności. Scale controller czyta każdą kolejkę control co 10 sekund. Przy domyślnych 4 partycjach to około 43 000 transakcji storage’u dziennie, zanim kod ruszy.
- Sufit na klucz. Microsoft podaje cel 64 operacji encji na sekundę. Dużo jak na checkpoint, ściana przy czymkolwiek większym.
- Braki w Pythonie. Encje nie mogą sygnalizować innych encji, a sekcji krytycznych nie ma wcale.
- Ciche błędy.
signal_entitydziała w jedną stronę. Wołający nie zobaczy ani wyniku, ani wyjątku. - Wolna praca lokalna. Każde uruchomienie wymaga emulatora i zdrowego task huba.
Najpierw nazwij stan, potem wybierz magazyn
| Stan | Przykład | Użyj |
|---|---|---|
| Brak | Odczyt bloba, zapis bloba | Nic |
| Kursor | Ostatni przetworzony timestamp | Wiersz w Table Storage |
| Ochrona przed duplikatem | „ID abc jest zrobione” | Table albo Cosmos z TTL |
| Wyłączny dostęp | Jeden pisarz na partycję | Blob lease |
| Kolejność per klucz | Wszystkie zdarzenia klienta 42 | Sesje Service Bus |
| Długie oczekiwanie | Akceptacja trwająca trzy dni | Durable Functions |
Pierwsze pięć wierszy ma tańsze odpowiedzi niż silnik orkiestracji.
Wiersz checkpointu
Zapis warunkowy daje ci bezpieczeństwo, które wcześniej dawała encja:
table.update_entity(
{"PartitionKey": stream, "RowKey": "cursor", "last_seen": value},
mode=UpdateMode.REPLACE,
etag=etag,
match_condition=MatchConditions.IfNotModified,
)
Gdy inny worker zmieni wiersz pierwszy, usługa zwraca HTTP 412, a SDK rzuca ResourceModifiedError. Ten jeden test zastępuje serializację zapisów przez encję. Odczytaj wiersz ponownie i zdecyduj.
Trzy zasady pilnują poprawności
- Najpierw wykonaj pracę, kursor zapisz na końcu. Crash powtórzy wtedy okno, zamiast je zgubić.
- Zrób każdy zapis idempotentnym.
upload_blob(overwrite=False)na deterministycznej nazwie to kompletne zabezpieczenie. - Odrzucaj stare wiadomości. Porównaj numer sekwencyjny, bo kolejki dostarczają poza kolejnością.
Kiedy zostać przy Durable Functions
Zostaw silnik, gdy problemem jest sam workflow:
- Krok czeka dłużej niż timeout funkcji, na przykład trzy dni na akceptację.
- Rozsyłasz pracę na 500 shardów i potrzebujesz realnej obsługi błędów przy powrocie.
- Praca w locie musi przeżyć wdrożenie.
- Orkiestracja już działa i zarabia na siebie.
Jeśli zostajesz, przejdź na Durable Task Scheduler. Znika konto storage i rachunek za polling, a istniejące aplikacje migrują bez zmian w kodzie.
Nazwij swój stan precyzyjnie. Gdy ta nazwa brzmi „ostatnia rzecz, którą przetworzyłem”, zapisz ją do wiersza z ETagiem i usuń silnik.