Zarządzanie stanem w Azure Functions bez Durable Functions

Hub Durable Functions z tabelami i kolejkami obok wiersza checkpointu.

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_entity dział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

  1. Najpierw wykonaj pracę, kursor zapisz na końcu. Crash powtórzy wtedy okno, zamiast je zgubić.
  2. Zrób każdy zapis idempotentnym. upload_blob(overwrite=False) na deterministycznej nazwie to kompletne zabezpieczenie.
  3. 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.

Źródła