Trwałe aranżacje
Durable Functions to rozszerzenie usługi Azure Functions. Za pomocą funkcji orkiestratora można organizować wykonywanie innych funkcji Durable w aplikacji funkcji. Funkcje programu Orchestrator mają następujące cechy:
- Funkcje programu Orchestrator definiują przepływy pracy funkcji przy użyciu kodu proceduralnego. Nie są potrzebne żadne schematy deklaratywne ani projektanci.
- Funkcje programu Orchestrator mogą wywoływać inne funkcje trwałe synchronicznie i asynchronicznie. Dane wyjściowe z wywoływanych funkcji można niezawodnie zapisywać w zmiennych lokalnych.
- Funkcje programu Orchestrator są trwałe i niezawodne. Postęp wykonywania jest automatycznie sprawdzany, gdy funkcja "awaits" lub "yields". Możliwość odtwarzania procesu lub ponownego uruchamiania maszyny wirtualnej bez utraty stanu lokalnego.
- Funkcje programu Orchestrator mogą być długotrwałe. Łączna żywotność wystąpienia orkiestracji może wynosić sekundy, dni, miesiące lub niekończące się zakończenie.
Ten artykuł zawiera omówienie funkcji orkiestratora i sposobu ich rozwiązywania różnych wyzwań związanych z programowaniem aplikacji. Jeśli nie znasz jeszcze typów funkcji dostępnych w aplikacji Durable Functions, przeczytaj artykuł Durable Function types (Typy funkcji durable).
Tożsamość orkiestracji
Każde wystąpienie orkiestracji ma identyfikator wystąpienia (znany również jako identyfikator wystąpienia). Domyślnie każdy identyfikator wystąpienia jest automatycznie wygenerowanym identyfikatorem GUID. Jednak identyfikatory wystąpień mogą być również dowolną wartością ciągu wygenerowaną przez użytkownika. Każdy identyfikator wystąpienia orkiestracji musi być unikatowy w centrum zadań.
Poniżej przedstawiono niektóre reguły dotyczące identyfikatorów wystąpień:
- Identyfikatory wystąpień muszą mieć od 1 do 100 znaków.
- Identyfikatory wystąpień nie mogą rozpoczynać się od
@
. - Identyfikatory wystąpień nie mogą zawierać
/
znaków ,\
,#
lub?
. - Identyfikatory wystąpień nie mogą zawierać znaków sterujących.
Uwaga
Zwykle zaleca się używanie automatycznie wygenerowanych identyfikatorów wystąpień, jeśli jest to możliwe. Identyfikatory wystąpień generowanych przez użytkownika są przeznaczone dla scenariuszy, w których istnieje mapowanie jeden do jednego między wystąpieniem aranżacji a inną jednostką specyficzną dla aplikacji, taką jak zamówienie zakupu lub dokument.
Ponadto rzeczywiste wymuszanie reguł ograniczeń znaków może się różnić w zależności od dostawcy magazynu używanego przez aplikację. Aby zapewnić prawidłowe zachowanie i zgodność, zdecydowanie zaleca się przestrzeganie wymienionych wcześniej reguł identyfikatora wystąpienia.
Identyfikator wystąpienia orkiestracji jest wymaganym parametrem dla większości operacji zarządzania wystąpieniami. Są one również ważne dla diagnostyki, takich jak wyszukiwanie danych śledzenia aranżacji w aplikacji Szczegółowe informacje na potrzeby rozwiązywania problemów lub analizy. Z tego powodu zaleca się zapisanie identyfikatorów wygenerowanych wystąpień w określonej lokalizacji zewnętrznej (na przykład w dziennikach bazy danych lub w dziennikach aplikacji), gdzie można je łatwo odwołać później.
Niezawodność
Funkcje programu Orchestrator niezawodnie utrzymują stan wykonywania przy użyciu wzorca projektowania określania źródła zdarzeń. Zamiast bezpośrednio przechowywać bieżący stan aranżacji, struktura Durable Task Framework używa magazynu tylko do dołączania do rejestrowania pełnej serii akcji, które podejmuje orkiestracja funkcji. Magazyn tylko do dołączania ma wiele korzyści w porównaniu do "dumpingu" stanu pełnego środowiska uruchomieniowego. Korzyści obejmują zwiększoną wydajność, skalowalność i czas odpowiedzi. Uzyskasz również spójność ostateczną dla danych transakcyjnych i pełnych dzienników inspekcji i historii. Dzienniki inspekcji obsługują niezawodne akcje wyrównywujące.
Rozszerzenie Durable Functions używa przezroczystego określania źródła zdarzeń. W tle await
operator (C#) lub yield
(JavaScript/Python) w funkcji orkiestratora daje kontrolę nad wątkiem orkiestratora z powrotem do dyspozytora Durable Task Framework. W przypadku języka Java nie ma specjalnego słowa kluczowego języka. Zamiast tego wywołanie .await()
zadania spowoduje powrót kontroli do dyspozytora za pośrednictwem niestandardowego Throwable
polecenia . Dyspozytor zatwierdza wszystkie nowe akcje zaplanowane przez funkcję orkiestratora (np. wywoływanie co najmniej jednej funkcji podrzędnej lub planowanie trwałego czasomierza) do magazynu. Przezroczysta akcja zatwierdzania aktualizuje historię wykonywania wystąpienia orkiestracji, dołączając wszystkie nowe zdarzenia do magazynu, podobnie jak dziennik tylko do dołączania. Podobnie akcja zatwierdzania tworzy komunikaty w magazynie, aby zaplanować rzeczywistą pracę. W tym momencie funkcję orkiestratora można zwolnić z pamięci. Domyślnie rozszerzenie Durable Functions używa usługi Azure Storage jako magazynu stanu środowiska uruchomieniowego, ale inni dostawcy magazynu są również obsługiwani.
Gdy funkcja orkiestracji ma więcej pracy do wykonania (na przykład zostanie odebrany komunikat odpowiedzi lub wygaśnie trwały czasomierz), orkiestrator wznawia i ponownie wykonuje całą funkcję od początku, aby ponownie skompilować stan lokalny. Podczas odtwarzania, jeśli kod próbuje wywołać funkcję (lub wykonać inną pracę asynchroniczną), struktura Durable Task Framework skonsultuje się z historią wykonywania bieżącej aranżacji. Jeśli okaże się, że funkcja działania została już wykonana i przyniosły wynik, odtwarza wynik tej funkcji , a kod orkiestratora nadal działa. Odtwarzanie będzie kontynuowane do momentu zakończenia kodu funkcji lub do czasu zaplanowania nowej pracy asynchronicznych.
Uwaga
Aby wzorzec odtwarzania działał prawidłowo i niezawodnie, kod funkcji orkiestratora musi być deterministyczny. Niedeterministyczny kod orkiestratora może spowodować błędy środowiska uruchomieniowego lub inne nieoczekiwane zachowanie. Aby uzyskać więcej informacji na temat ograniczeń kodu dla funkcji orkiestratora, zobacz dokumentację ograniczeń kodu funkcji orkiestratora.
Uwaga
Jeśli funkcja orkiestratora emituje komunikaty dziennika, zachowanie odtwarzania może spowodować emitowanie zduplikowanych komunikatów dziennika. Zobacz temat Rejestrowanie, aby dowiedzieć się więcej o tym, dlaczego to zachowanie występuje i jak obejść ten problem.
Historia orkiestracji
Zachowanie określania źródła zdarzeń struktury Durable Task Framework jest ściśle powiązane z kodem funkcji orkiestratora, który piszesz. Załóżmy, że masz funkcję orkiestratora łańcucha działań, podobną do następującej funkcji orkiestratora:
Uwaga
Wersja 4 modelu programowania Node.js dla usługi Azure Functions jest ogólnie dostępna. Nowy model w wersji 4 został zaprojektowany z myślą o bardziej elastycznym i intuicyjnym środowisku dla deweloperów języków JavaScript i TypeScript. Dowiedz się więcej o różnicach między wersjami 3 i v4 w przewodniku migracji.
W poniższych fragmentach kodu javaScript (PM4) oznacza model programowania W wersji 4, nowe środowisko.
[FunctionName("HelloCities")]
public static async Task<List<string>> Run(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
var outputs = new List<string>();
outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo"));
outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle"));
outputs.Add(await context.CallActivityAsync<string>("SayHello", "London"));
// returns ["Hello Tokyo!", "Hello Seattle!", "Hello London!"]
return outputs;
}
Za każdym razem, gdy funkcja działania jest zaplanowana, platforma Durable Task Framework wskazuje stan wykonywania funkcji w pewnym trwałym zapleczu magazynu (usługa Azure Table Storage domyślnie). Ten stan jest określany jako historia aranżacji.
Tabela historii
Ogólnie rzecz biorąc, struktura Durable Task Framework wykonuje następujące czynności w każdym punkcie kontrolnym:
- Zapisuje historię wykonywania w magazynie trwałym.
- Kolejkuje komunikaty dla funkcji, które program orchestrator chce wywołać.
- Kolejkuje komunikaty dla samego koordynatora — na przykład trwałe komunikaty czasomierza.
Po zakończeniu punktu kontrolnego funkcja orkiestratora może zostać usunięta z pamięci, dopóki nie będzie więcej pracy.
Uwaga
Usługa Azure Storage nie zapewnia żadnych gwarancji transakcyjnych między zapisywaniem danych w usłudze Table Storage i kolejkami. Aby obsłużyć błędy, dostawca usługi Durable Functions w usłudze Azure Storage używa wzorców spójności ostatecznej. Te wzorce zapewniają, że żadne dane nie zostaną utracone w przypadku awarii lub utraty łączności w środku punktu kontrolnego. Alternatywni dostawcy magazynu, tacy jak dostawca magazynu Durable Functions MSSQL, mogą zapewnić większe gwarancje spójności.
Po zakończeniu historia przedstawionej wcześniej funkcji wygląda podobnie do poniższej tabeli w usłudze Azure Table Storage (skróconej dla celów ilustracyjnych):
PartitionKey (InstanceId) | EventType | Sygnatura czasowa | Dane wejściowe | Nazwisko | Result | Stan |
---|---|---|---|---|---|---|
eaee885b | WykonanieStarted | 2021-05-05T18:45:28.852Z | null | HelloCities | ||
eaee885b | OrchestratorStarted | 2021-05-05T18:45:32.362Z | ||||
eaee885b | Zadanieschedulowane | 2021-05-05T18:45:32.670Z | SayHello | |||
eaee885b | OrchestratorCompleted | 2021-05-05T18:45:32.670Z | ||||
eaee885b | Zadaniezupełnione | 2021-05-05T18:45:34.201Z | ""Hello Tokyo!""" | |||
eaee885b | OrchestratorStarted | 2021-05-05T18:45:34.232Z | ||||
eaee885b | Zadanieschedulowane | 2021-05-05T18:45:34.435Z | SayHello | |||
eaee885b | OrchestratorCompleted | 2021-05-05T18:45:34.435Z | ||||
eaee885b | Zadaniezupełnione | 2021-05-05T18:45:34.763Z | ""Hello Seattle!""" | |||
eaee885b | OrchestratorStarted | 2021-05-05T18:45:34.857Z | ||||
eaee885b | Zadanieschedulowane | 2021-05-05T18:45:34.857Z | SayHello | |||
eaee885b | OrchestratorCompleted | 2021-05-05T18:45:34.857Z | ||||
eaee885b | Zadaniezupełnione | 2021-05-05T18:45:34.919Z | ""Hello London!""" | |||
eaee885b | OrchestratorStarted | 2021-05-05T18:45:35.032Z | ||||
eaee885b | OrchestratorCompleted | 2021-05-05T18:45:35.044Z | ||||
eaee885b | WykonanieZupełnione | 2021-05-05T18:45:35.044Z | "["Hello Tokyo!"","Hello Seattle!"","Hello London!""]" | Ukończone |
Kilka notatek dotyczących wartości kolumn:
- PartitionKey: zawiera identyfikator wystąpienia aranżacji.
- EventType: reprezentuje typ zdarzenia. Szczegółowe opisy wszystkich typów zdarzeń historii można znaleźć tutaj.
- Sygnatura czasowa: sygnatura czasowa UTC zdarzenia historii.
- Nazwa: nazwa wywoływanej funkcji.
- Dane wejściowe: dane wejściowe w formacie JSON funkcji.
- Wynik: dane wyjściowe funkcji, czyli jej wartość zwracana.
Ostrzeżenie
Chociaż jest to przydatne jako narzędzie do debugowania, nie należy stosować żadnej zależności od tej tabeli. Może się to zmienić w miarę rozwoju rozszerzenia Durable Functions.
Za każdym razem, gdy funkcja jest wznawiana po oczekiwaniu na ukończenie zadania, struktura Durable Task Framework ponownie uruchamia funkcję orkiestratora od podstaw. Na każdym ponownym uruchomieniu skonsultuje się z historią wykonywania, aby określić, czy bieżące zadanie asynchroniczne zostało ukończone. Jeśli historia wykonywania pokazuje, że zadanie zostało już ukończone, struktura odtwarza dane wyjściowe tego zadania i przechodzi do następnego zadania. Ten proces będzie kontynuowany do czasu odtworzenia całej historii wykonywania. Po ponownym odtworzeniu bieżącej historii wykonywania zmienne lokalne zostaną przywrócone do poprzednich wartości.
Funkcje i wzorce
W następnych sekcjach opisano funkcje i wzorce funkcji orkiestratora.
Orkiestracje podrzędne
Funkcje programu Orchestrator mogą wywoływać funkcje działania, ale także inne funkcje orkiestratora. Na przykład można utworzyć większą aranżację z biblioteki funkcji orkiestratora. Możesz też uruchomić wiele wystąpień funkcji orkiestratora równolegle.
Aby uzyskać więcej informacji i przykłady, zobacz artykuł Sub-orchestrations (Sub-orchestrations).
Trwałe czasomierze
Orkiestracje mogą planować trwałe czasomierze w celu zaimplementowania opóźnień lub skonfigurowania obsługi limitu czasu w akcjach asynchronicznych. Używaj trwałych czasomierzy w funkcjach orkiestratora zamiast natywnych dla języka interfejsów API "uśpienia".
Aby uzyskać więcej informacji i przykłady, zobacz artykuł Durable timers (Czasomierze trwałe).
Zdarzenia zewnętrzne
Funkcje programu Orchestrator mogą czekać na zdarzenia zewnętrzne, aby zaktualizować wystąpienie orkiestracji. Ta funkcja Durable Functions często jest przydatna do obsługi interakcji człowieka lub innych wywołań zwrotnych zewnętrznych.
Aby uzyskać więcej informacji i przykłady, zobacz artykuł Zdarzenia zewnętrzne.
Obsługa błędów
Funkcje programu Orchestrator mogą używać funkcji obsługi błędów języka programowania. Istniejące wzorce, takie jak try
/catch
, są obsługiwane w kodzie orkiestracji.
Funkcje programu Orchestrator mogą również dodawać zasady ponawiania do wywoływanych przez nich funkcji działania lub podarantora. Jeśli działanie lub funkcja podrzędna orkiestratora zakończy się niepowodzeniem z wyjątkiem, określone zasady ponawiania mogą automatycznie opóźnić i ponowić próbę wykonania do określonej liczby razy.
Uwaga
Jeśli w funkcji orkiestratora występuje nieobsługiwany wyjątek, wystąpienie orkiestracji zostanie ukończone w Failed
stanie. Nie można ponowić próby wystąpienia orkiestracji po jego awarii.
Aby uzyskać więcej informacji i przykłady, zobacz artykuł Obsługa błędów.
Sekcje krytyczne (Durable Functions 2.x, obecnie tylko .NET)
Wystąpienia orkiestracji są jednowątkowe, więc nie trzeba martwić się o warunki wyścigu w ramach aranżacji. Jednak warunki wyścigu są możliwe, gdy aranżacje wchodzą w interakcje z systemami zewnętrznymi. Aby ograniczyć warunki wyścigu podczas interakcji z systemami zewnętrznymi, funkcje orkiestratora mogą definiować sekcje krytyczne przy użyciu LockAsync
metody na platformie .NET.
Poniższy przykładowy kod przedstawia funkcję orkiestratora, która definiuje sekcję krytyczną. Wprowadza on sekcję krytyczną LockAsync
przy użyciu metody . Ta metoda wymaga przekazania co najmniej jednego odwołania do jednostki trwałej, która trwale zarządza stanem blokady. Tylko jedno wystąpienie tej aranżacji może jednocześnie wykonać kod w sekcji krytycznej.
[FunctionName("Synchronize")]
public static async Task Synchronize(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
var lockId = new EntityId("LockEntity", "MyLockIdentifier");
using (await context.LockAsync(lockId))
{
// critical section - only one orchestration can enter at a time
}
}
Element LockAsync
uzyskuje trwałe blokady i zwraca element kończący sekcję krytyczną IDisposable
po usunięciu. Tego IDisposable
wyniku można użyć razem z blokiem using
, aby uzyskać składniową reprezentację sekcji krytycznej. Gdy funkcja orkiestratora wchodzi w sekcję krytyczną, tylko jedno wystąpienie może wykonać ten blok kodu. Wszystkie inne wystąpienia, które spróbują wprowadzić sekcję krytyczną, zostaną zablokowane do momentu zamknięcia poprzedniego wystąpienia sekcji krytycznej.
Funkcja sekcji krytycznej jest również przydatna do koordynowania zmian w jednostkach trwałych. Aby uzyskać więcej informacji na temat sekcji krytycznych, zobacz temat Trwałe jednostki "Koordynacja jednostek".
Uwaga
Sekcje krytyczne są dostępne w rozszerzeniu Durable Functions 2.0. Obecnie ta funkcja implementuje tylko orkiestracje in-proc platformy .NET. Jednostki i sekcje krytyczne nie są jeszcze dostępne w usłudze Durable Functions dla procesu roboczego izolowanego przez dotnet.
Wywoływanie punktów końcowych HTTP (Durable Functions 2.x)
Funkcje programu Orchestrator nie mogą wykonywać operacji we/wy zgodnie z opisem w artykule Ograniczenia kodu funkcji orkiestratora. Typowym obejściem tego ograniczenia jest zawijanie dowolnego kodu, który musi wykonać operacje we/wy w funkcji działania. Aranżacje, które często współdziałają z systemami zewnętrznymi, używają funkcji działań w celu wykonywania wywołań HTTP i zwracania wyniku do aranżacji.
Aby uprościć ten typowy wzorzec, funkcje orkiestratora mogą używać CallHttpAsync
metody do bezpośredniego wywoływania interfejsów API HTTP.
[FunctionName("CheckSiteAvailable")]
public static async Task CheckSiteAvailable(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
Uri url = context.GetInput<Uri>();
// Makes an HTTP GET request to the specified endpoint
DurableHttpResponse response =
await context.CallHttpAsync(HttpMethod.Get, url);
if ((int)response.StatusCode == 400)
{
// handling of error codes goes here
}
}
Oprócz obsługi podstawowych wzorców żądań/odpowiedzi metoda obsługuje automatyczną obsługę typowych wzorców sondowania HTTP 202 asynchronicznych, a także obsługuje uwierzytelnianie za pomocą usług zewnętrznych przy użyciu tożsamości zarządzanych.
Aby uzyskać więcej informacji i zapoznać się ze szczegółowymi przykładami, zobacz artykuł dotyczący funkcji HTTP.
Uwaga
Wywoływanie punktów końcowych HTTP bezpośrednio z funkcji orkiestratora jest dostępne w rozszerzeniu Durable Functions 2.0 lub nowszym.
Przekazywanie wielu parametrów
Nie można przekazać wielu parametrów bezpośrednio do funkcji działania. Zaleceniem jest przekazanie tablicy obiektów lub obiektów złożonych.
Na platformie .NET można również użyć obiektów ValueTuple . W poniższym przykładzie są używane nowe funkcje elementu ValueTuple dodane z językiem C# 7:
[FunctionName("GetCourseRecommendations")]
public static async Task<object> RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
string major = "ComputerScience";
int universityYear = context.GetInput<int>();
object courseRecommendations = await context.CallActivityAsync<object>(
"CourseRecommendations",
(major, universityYear));
return courseRecommendations;
}
[FunctionName("CourseRecommendations")]
public static async Task<object> Mapper([ActivityTrigger] IDurableActivityContext inputs)
{
// parse input for student's major and year in university
(string Major, int UniversityYear) studentInfo = inputs.GetInput<(string, int)>();
// retrieve and return course recommendations by major and university year
return new
{
major = studentInfo.Major,
universityYear = studentInfo.UniversityYear,
recommendedCourses = new []
{
"Introduction to .NET Programming",
"Introduction to Linux",
"Becoming an Entrepreneur"
}
};
}