Ograniczenia kodu funkcji programu Orchestrator

Durable Functions to rozszerzenie Azure Functions, które umożliwia tworzenie aplikacji stanowych. Możesz użyć funkcji orkiestratora , aby zorganizować wykonywanie innych funkcji trwałych w aplikacji funkcji. Funkcje programu Orchestrator są stanowe, niezawodne i potencjalnie długotrwałe.

Ograniczenia kodu orkiestratora

Funkcje orkiestratora używają określania źródła zdarzeń w celu zapewnienia niezawodnego wykonywania i utrzymania stanu zmiennej lokalnej. Zachowanie odtwarzania kodu orkiestratora tworzy ograniczenia dotyczące typu kodu, który można napisać w funkcji orkiestratora. Na przykład funkcje orkiestratora muszą być deterministyczne: funkcja orkiestratora będzie odtwarzana wiele razy i musi generować ten sam wynik za każdym razem.

Używanie deterministycznych interfejsów API

Ta sekcja zawiera kilka prostych wskazówek, które pomagają zagwarantować, że kod jest deterministyczny.

Funkcje programu Orchestrator mogą wywoływać dowolny interfejs API w ich językach docelowych. Jednak ważne jest, aby funkcje orkiestratora wywoływać tylko deterministyczne interfejsy API. Deterministyczny interfejs API to interfejs API, który zawsze zwraca tę samą wartość, biorąc pod uwagę te same dane wejściowe, niezależnie od tego, kiedy lub jak często jest wywoływany.

Poniższe sekcje zawierają wskazówki dotyczące interfejsów API i wzorców, których należy unikać, ponieważ nie są deterministyczne. Te ograniczenia dotyczą tylko funkcji orkiestratora. Inne typy funkcji nie mają takich ograniczeń.

Uwaga

Poniżej opisano kilka typów ograniczeń kodu. Ta lista nie jest niestety kompleksowa i niektóre przypadki użycia mogą nie być omówione. Najważniejszą rzeczą, którą należy wziąć pod uwagę podczas pisania kodu orkiestratora, jest to, czy używany interfejs API jest deterministyczny. Po zapoznaniu się z myśleniem w ten sposób możesz łatwo zrozumieć, które interfejsy API są bezpieczne do użycia i które nie są bez konieczności odwoływania się do tej udokumentowanej listy.

Daty i godziny

Interfejsy API zwracające bieżącą datę lub godzinę są nieokreślone i nigdy nie powinny być używane w funkcjach orkiestratora. Dzieje się tak, ponieważ każda powtórka funkcji orkiestratora generuje inną wartość. Zamiast tego należy użyć interfejsu API Durable Functions równoważnego do uzyskania bieżącej daty lub godziny, która pozostaje spójna w przypadku odtwarzania.

Nie używaj DateTime.Nowinterfejsów API , DateTime.UtcNowlub równoważnych do pobierania bieżącego czasu. Należy unikać klas, takich jak Stopwatch . W przypadku funkcji orkiestratora in-process platformy .NET użyj IDurableOrchestrationContext.CurrentUtcDateTime właściwości , aby uzyskać bieżący czas. W przypadku funkcji orkiestratora izolowanego platformy .NET użyj TaskOrchestrationContext.CurrentDateTimeUtc właściwości , aby uzyskać bieżący czas.

DateTime startTime = context.CurrentUtcDateTime;
// do some work
TimeSpan totalTime = context.CurrentUtcDateTime.Subtract(startTime);

Identyfikatory GUID i identyfikatory UUD

Interfejsy API zwracające losowy identyfikator GUID lub identyfikator UUID są nieokreślone, ponieważ wygenerowana wartość jest inna dla każdego odtwarzania. W zależności od używanego języka może być dostępny wbudowany interfejs API do generowania deterministycznych identyfikatorów GUID lub identyfikatorów UUID. W przeciwnym razie użyj funkcji activity, aby zwrócić losowo wygenerowany identyfikator GUID lub identyfikator UUID.

Nie używaj interfejsów API, takich jak Guid.NewGuid() generowanie losowych identyfikatorów GUID. Zamiast tego użyj interfejsu API obiektu NewGuid() kontekstu, aby wygenerować losowy identyfikator GUID, który jest bezpieczny dla odtwarzania orkiestratora.

Guid randomGuid = context.NewGuid();

Uwaga

Identyfikatory GUID generowane za pomocą interfejsów API kontekstu aranżacji to identyfikatory UUID typu 5.

Liczby losowe

Funkcja działania umożliwia zwracanie liczb losowych do funkcji orkiestratora. Zwracane wartości funkcji działań są zawsze bezpieczne do odtwarzania, ponieważ są zapisywane w historii aranżacji.

Alternatywnie generator liczb losowych o stałej wartości nasion może być używany bezpośrednio w funkcji orkiestratora. Takie podejście jest bezpieczne, o ile ta sama sekwencja liczb jest generowana dla każdej powtórki orkiestracji.

Powiązania

Funkcja orkiestratora nie może używać żadnych powiązań, w tym nawet powiązań klienta orkiestracji i klienta jednostki . Zawsze używaj powiązań wejściowych i wyjściowych z poziomu funkcji klienta lub działania. Jest to ważne, ponieważ funkcje orkiestratora mogą być odtwarzane wiele razy, powodując nieokreślone i zduplikowane operacje we/wy z systemami zewnętrznymi.

Zmienne statyczne

Unikaj używania zmiennych statycznych w funkcjach orkiestratora, ponieważ ich wartości mogą się zmieniać w czasie, co powoduje nieokreślone zachowanie środowiska uruchomieniowego. Zamiast tego należy użyć stałych lub ograniczyć użycie zmiennych statycznych do funkcji działania.

Uwaga

Nawet poza funkcjami orkiestratora używanie zmiennych statycznych w Azure Functions może być problematyczne z różnych powodów, ponieważ nie ma gwarancji, że stan statyczny będzie trwały w wielu wykonaniach funkcji. Należy unikać zmiennych statycznych z wyjątkiem bardzo specyficznych przypadków użycia, takich jak buforowanie w pamięci w funkcji działania lub jednostki.

Zmienne środowiskowe

Nie używaj zmiennych środowiskowych w funkcjach orkiestratora. Ich wartości mogą ulec zmianie w czasie, co powoduje nieokreślone zachowanie środowiska uruchomieniowego. Jeśli funkcja orkiestratora wymaga konfiguracji zdefiniowanej w zmiennej środowiskowej, musisz przekazać wartość konfiguracji do funkcji orkiestratora jako dane wejściowe lub jako wartość zwracaną funkcji działania.

Sieć i protokół HTTP

Używanie funkcji działań do wykonywania wychodzących wywołań sieciowych. Jeśli musisz wykonać wywołanie HTTP z funkcji orkiestratora, możesz również użyć trwałych interfejsów API HTTP.

Interfejsy API blokujące wątki

Blokowanie interfejsów API, takich jak "uśpienie", może powodować problemy z wydajnością i skalowaniem funkcji orkiestratora i należy unikać. W planie Azure Functions Zużycie mogą nawet spowodować niepotrzebne opłaty za czas wykonania. Użyj alternatyw do blokowania interfejsów API, gdy są dostępne. Na przykład użyj czasomierzy Durable , aby utworzyć opóźnienia, które są bezpieczne do odtwarzania i nie są uwzględniane w czasie wykonywania funkcji orkiestratora.

Asynchroniczne interfejsy API

Kod programu Orchestrator nigdy nie może uruchomić żadnej operacji asynchronicznych, z wyjątkiem tych zdefiniowanych przez obiekt kontekstu wyzwalacza orkiestracji. Na przykład nigdy nie używaj Task.Runparametrów , Task.Delayi HttpClient.SendAsync na platformie .NET lub setTimeoutsetInterval w języku JavaScript. Funkcja orkiestratora powinna planować tylko pracę asynchroniczną przy użyciu interfejsów API zestawu Durable SDK, takich jak funkcje działań planowania. Wszelkie inne wywołania asynchroniczne powinny być wykonywane wewnątrz funkcji działania.

Asynchroniczne funkcje języka JavaScript

Zawsze deklaruj funkcje orkiestratora JavaScript jako funkcje generatora synchronicznego. Nie można deklarować funkcji orkiestratora Języka JavaScript, ponieważ async środowisko uruchomieniowe Node.js nie gwarantuje, że funkcje asynchroniczne są deterministyczne.

Koprocedyny języka Python

Nie można deklarować funkcji orkiestratora języka Python jako koprocedułów. Innymi słowy, nigdy nie deklaruj funkcji orkiestratora języka Python za pomocą słowa kluczowegoasync, ponieważ semantyka koprocedutyny nie jest zgodna z modelem odtwarzania Durable Functions. Zawsze należy zadeklarować funkcje orkiestratora języka Python jako generatory, co oznacza, że należy oczekiwać context , że interfejs API będzie używany yield zamiast await.

Interfejsy API wątkowania platformy .NET

Rozszerzenie Durable Task Framework uruchamia kod orkiestratora w jednym wątku i nie może wchodzić w interakcje z żadnymi innymi wątkami. Uruchamianie kontynuacji asynchronicznych w wątku puli procesów roboczych wykonanie orkiestracji może spowodować nieokreślone wykonanie lub zakleszczenia. Z tego powodu funkcje orkiestratora prawie nigdy nie powinny używać interfejsów API wątkowania. Na przykład nigdy nie należy używać ConfigureAwait(continueOnCapturedContext: false) w funkcji orkiestratora. Dzięki temu kontynuacje zadań będą uruchamiane w oryginalnej SynchronizationContextfunkcji orkiestratora .

Uwaga

Struktura Durable Task Framework próbuje wykryć przypadkowe użycie wątków innych niż orkiestrator w funkcjach orkiestratora. W przypadku znalezienia naruszenia struktura zgłasza wyjątek NonDeterministicOrchestrationException . Jednak to zachowanie wykrywania nie spowoduje przechwycenia wszystkich naruszeń i nie powinno być od niego zależne.

Przechowywanie wersji

Trwała aranżacja może działać w sposób ciągły przez dni, miesiące, lata, a nawet wiecznie. Wszelkie aktualizacje kodu wprowadzone w aplikacjach Durable Functions, które mają wpływ na niedokończone aranżacje, mogą spowodować przerwanie zachowania odtwarzania orkiestracji. Dlatego ważne jest, aby uważnie planować podczas wprowadzania aktualizacji kodu. Aby uzyskać bardziej szczegółowy opis sposobu przechowywania wersji kodu, zobacz artykuł dotyczący przechowywania wersji.

Zadania trwałe

Uwaga

W tej sekcji opisano szczegóły implementacji wewnętrznej platformy Durable Task Framework. Można używać funkcji trwałych bez znajomości tych informacji. Ma to na celu tylko ułatwienie zrozumienia zachowania odtwarzania.

Zadania, które mogą bezpiecznie czekać w funkcjach orkiestratora, są czasami określane jako zadania trwałe. Rozszerzenie Durable Task Framework tworzy te zadania i zarządza nimi. Przykłady to zadania zwracane przez CallActivityAsyncfunkcje orkiestratora platformy , WaitForExternalEventi CreateTimer platformy .NET.

Te trwałe zadania są zarządzane wewnętrznie przez listę TaskCompletionSource obiektów na platformie .NET. Podczas odtwarzania te zadania są tworzone w ramach wykonywania kodu orkiestratora. Są one gotowe, ponieważ dyspozytor wylicza odpowiadające im zdarzenia historii.

Zadania są wykonywane synchronicznie przy użyciu jednego wątku do momentu ponownego odtworzenia całej historii. Zadania trwałe, które nie zostały ukończone po zakończeniu odtwarzania historii, mają wykonane odpowiednie działania. Na przykład komunikat może zostać przesłany do kolejki w celu wywołania funkcji działania.

Opis zachowania środowiska uruchomieniowego w tej sekcji powinien ułatwić zrozumienie, dlaczego funkcja orkiestratora nie może używać await ani yield w nieuruchomialnym zadaniu. Istnieją dwie przyczyny: wątek dyspozytora nie może czekać na zakończenie zadania, a każde wywołanie zwrotne przez to zadanie może potencjalnie uszkodzić stan śledzenia funkcji orkiestratora. Niektóre kontrole środowiska uruchomieniowego są stosowane w celu ułatwienia wykrywania tych naruszeń.

Aby dowiedzieć się więcej na temat sposobu wykonywania funkcji orkiestratora przez platformę Durable Task Framework, zapoznaj się z kodem źródłowym rozszerzenia Durable Task w witrynie GitHub. W szczególności zobacz TaskOrchestrationExecutor.cs i TaskOrchestrationContext.cs.

Następne kroki