Zarządzanie stanem w Azure Functions bez Durable Functions

Durable Functions to silnik workflow i domyślna odpowiedź, gdy funkcja musi trzymać stan. Jest to jednak rozwiązanie generyczne, robione pod ogół klientów Azure, przez co ma podwyższoną złożoność. Dostarczają je deweloperzy Azure, więc problemy ze stabilnością zdarzają się częściej.
Gdy twoim stanem jest kursor, flaga albo licznik, prostsze opcje opisane niżej bywają lepszym wyborem.
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 |
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.