Cloud & IT Cert Prep · Lekcja

Durable Functions dla przepływów pracy ze stanem

Orkiestruj długotrwałe przepływy pracy za pomocą wzorców orkiestratora Durable Functions (fan-out/fan-in, chaining, monitor) oraz poznaj sposób tworzenia punktów kontrolnych stanu.

Lekcja 2 z 413 kroki

Durable Functions dla przepływów pracy ze stanem to bezpłatna lekcja Cloud & IT Cert Prep na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Cloud & IT Cert Prep, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Cloud & IT Cert Prep zawiera 4 lekcji w sumie.

Dlaczego Durable Functions?

Zwykłe funkcje Azure są bezstanowe — każde wywołanie działa niezależnie i nie pamięta poprzednich wywołań. Durable Functions rozszerza Azure Functions o możliwość tworzenia stanowych, długotrwałych przepływów pracy przy użyciu zwykłego kodu async/await. Durable Task Framework automatycznie zapisuje punkty kontrolne stanu w Azure Storage po każdym kroku, dzięki czemu przepływy pracy mogą przetrwać ponowne uruchomienie serwera, przekroczenie limitu czasu lub planowaną konserwację i wznowić działanie dokładnie w miejscu, w którym zostały przerwane.

Trzy typy funkcji

Durable Functions wprowadza trzy typy funkcji. Funkcja orkiestratora koordynuje cały przepływ pracy — wywołuje funkcje aktywności i oczekuje na wyniki przy użyciu yield lub await, nie blokując przy tym wątku. Funkcja aktywności wykonuje pojedynczą jednostkę pracy (wywołuje interfejs API, zapisuje dane w bazie danych) i jest jedynym miejscem, w którym powinny występować efekty uboczne. Funkcja encji przechowuje niewielkie fragmenty trwałego stanu (liczniki, flagi) pomiędzy wywołaniami.

// Client function (HTTP trigger) — starts the orchestration
module.exports = async function (context, req) {
  const client = df.getClient(context);
  const orderId = req.body.orderId;
  const instanceId = await client.startNew('OrderOrchestrator', undefined, { orderId });
  return client.createCheckStatusResponse(context.bindingData.req, instanceId);
};

Wzorzec łańcuchowy

Wzorzec łańcuchowy uruchamia funkcje aktywności sekwencyjnie, przekazując dane wyjściowe jednej funkcji jako dane wejściowe następnej. Orkiestrator oczekuje kolejno na zakończenie każdej aktywności. Jeśli dowolna aktywność zakończy się niepowodzeniem, przepływ pracy zostaje zatrzymany i można go ponownie uruchomić od nieudanego kroku. Jest to najprostszy wzorzec Durable Functions i nadaje się do przepływów pracy, w których każdy krok zależy od wyniku poprzedniego, na przykład potoków przetwarzania zamówień.

// Orchestrator: chaining pattern
const df = require('durable-functions');
module.exports = df.orchestrator(function* (context) {
  const orderId = context.df.getInput().orderId;

  const validated = yield context.df.callActivity('ValidateOrder', orderId);
  const charged   = yield context.df.callActivity('ChargePayment', validated);
  const shipped   = yield context.df.callActivity('ShipOrder', charged);

  return { status: 'shipped', trackingId: shipped.trackingId };
});

Wzorzec fan-out/fan-in

Wzorzec fan-out/fan-in uruchamia równolegle wiele funkcji aktywności i oczekuje na zakończenie wszystkich przed kontynuowaniem działania. Orkiestrator jednocześnie uruchamia wszystkie zadania za pomocą callActivity, nie oczekując na ich zakończenie, zbiera obiekty zadań w tablicy, a następnie wykonuje Task.all(). W przypadku niezależnych elementów pracy, takich jak przetwarzanie wielu plików, wywoływanie wielu interfejsów API lub operacje wsadowe, jest to znacznie szybsze niż przetwarzanie sekwencyjne.

// Orchestrator: fan-out / fan-in
module.exports = df.orchestrator(function* (context) {
  const items = context.df.getInput().items;

  // Fan-out: start all tasks in parallel
  const tasks = items.map(item => context.df.callActivity('ProcessItem', item));

  // Fan-in: wait for all tasks to complete
  const results = yield context.df.Task.all(tasks);

  return results;
});

Wzorzec monitorowania

Wzorzec monitorowania odpytuje system zewnętrzny w określonych odstępach czasu aż do spełnienia warunku — podobnie jak pętla odpytywania, ale w sposób w pełni trwały. Orkiestrator wywołuje aktywność w celu sprawdzenia stanu, czeka przez konfigurowalny odstęp czasu za pomocą createTimer, a następnie powtarza tę czynność. Ponieważ stan jest zapisywany w magazynie w punkcie kontrolnym pomiędzy kolejnymi odpytywaniami, orkiestrator nie zużywa zasobów obliczeniowych podczas oczekiwania, dzięki czemu rozwiązanie jest znacznie wydajniejsze niż podejście oparte na uśpionym zegarze.

// Orchestrator: monitor pattern (poll until job completes)
module.exports = df.orchestrator(function* (context) {
  const jobId = context.df.getInput().jobId;
  const expiry = new Date(context.df.currentUtcDateTime);
  expiry.setHours(expiry.getHours() + 24); // 24-hour timeout

  while (context.df.currentUtcDateTime < expiry) {
    const status = yield context.df.callActivity('GetJobStatus', jobId);
    if (status === 'completed') return { jobId, status };
    if (status === 'failed') throw new Error('Job failed');
    // Wait 30 seconds before next poll
    const nextCheck = new Date(context.df.currentUtcDateTime);
    nextCheck.setSeconds(nextCheck.getSeconds() + 30);
    yield context.df.createTimer(nextCheck);
  }
  throw new Error('Workflow timed out');
});

Wzorzec interakcji z użytkownikiem

Wzorzec interakcji z użytkownikiem wstrzymuje orkiestrację i oczekuje na zdarzenie zewnętrzne — na przykład zatwierdzenie przez kierownika. Orkiestrator wykonuje waitForExternalEvent, które może oczekiwać przez wiele dni lub tygodni bez zużywania zasobów obliczeniowych. System zewnętrzny (link zatwierdzenia w wiadomości e-mail, aplikacja mobilna, element webhook) wywołuje interfejs HTTP API Durable Functions, aby zgłosić zdarzenie i odblokować orkiestrację. W przypadku braku odpowiedzi warto połączyć ten wzorzec z zegarem, aby automatycznie zakończyć oczekiwanie i eskalować sprawę.

// Orchestrator: wait for human approval with timeout
module.exports = df.orchestrator(function* (context) {
  const request = context.df.getInput();

  yield context.df.callActivity('SendApprovalEmail', request);

  const timeout = df.Task.createTimer(context, new Date(Date.now() + 48 * 3600 * 1000));
  const approval = context.df.waitForExternalEvent('ApprovalResponse');

  const winner = yield context.df.Task.any([approval, timeout]);

  if (winner === approval) {
    const approved = winner.result;
    return approved ? 'Approved' : 'Rejected';
  } else {
    return 'Timed out — escalated';
  }
});

Ograniczenia orkiestratora

Funkcje orkiestratora mają istotne ograniczenia, ponieważ mogą być wielokrotnie odtwarzane na podstawie historii w celu odbudowania stanu. Muszą być deterministyczne — nie wolno używać Date.now() ani Math.random() ani wykonywać bezpośrednich wywołań wejścia-wyjścia. Zamiast tego należy używać context.df.currentUtcDateTime do uzyskiwania znaczników czasu oraz wywoływać funkcje aktywności dla wszystkich operacji wejścia-wyjścia. Rejestrowanie logów w treści orkiestratora spowoduje powstawanie zduplikowanych wpisów podczas odtwarzania; do rejestrowania logów należy używać funkcji aktywności.

// WRONG — non-deterministic, will cause replay bugs
module.exports = df.orchestrator(function* (context) {
  const now = new Date();          // Don't use Date()
  const rand = Math.random();       // Don't use Math.random()
  const data = await fetch('/api'); // Don't make HTTP calls directly
});

// CORRECT
module.exports = df.orchestrator(function* (context) {
  const now = context.df.currentUtcDateTime; // OK
  const data = yield context.df.callActivity('FetchData', null); // OK
});

Zarządzanie wystąpieniami: stan i kończenie

Każde uruchomienie orkiestracji ma unikatowy identyfikator wystąpienia, którego można używać do sprawdzania stanu, wysyłania zdarzeń lub kończenia wystąpienia. Interfejs HTTP API zarządzania Durable Functions udostępnia punkty końcowe do sprawdzania stanu (GET /instances/{id}), wysyłania zdarzeń (POST /instances/{id}/raiseEvent/{name}) i kończenia wystąpienia (POST /instances/{id}/terminate). Aby uzyskiwać programistyczny dostęp do tych operacji, należy używać powiązania klienta Durable w funkcjach.

// Client function: check orchestration status
module.exports = async function (context, req) {
  const client = df.getClient(context);
  const instanceId = req.params.instanceId;

  const status = await client.getStatus(instanceId, true, true, true);
  return {
    status: 200,
    body: {
      instanceId,
      runtimeStatus: status.runtimeStatus,
      customStatus: status.customStatus,
      output: status.output
    }
  };
};

Magazyn danych i wydajność

Durable Functions przechowuje historię orkiestracji, stan wystąpień i kolejki komunikatów między funkcjami na koncie Azure Storage Account (lub w magazynach Azure SQL/Netherite zapewniających większą przepustowość). Każdy punkt kontrolny powoduje zapis w Azure Table Storage i Azure Queue Storage. W scenariuszach wymagających dużej przepustowości (tysiące jednoczesnych orkiestracji) magazyn Netherite korzysta z Azure Event Hubs, zapewniając znacznie wyższą wydajność. Aby wykrywać wąskie gardła, należy monitorować głębokość kolejki orkiestracji.

// host.json: configure the Durable Task storage provider
{
  'version': '2.0',
  'extensions': {
    'durableTask': {
      'hubName': 'MyTaskHub',
      'storageProvider': {
        'type': 'azure',
        'connectionStringName': 'AzureWebJobsStorage',
        'controlQueueBatchSize': 32,
        'maxQueuePollingInterval': '00:00:02'
      }
    }
  }
}

Obsługa błędów i ponowienia

Funkcje aktywności mogą zgłaszać wyjątki, które są przekazywane z powrotem do orkiestratora jako TaskFailedException. Aby odpowiednio obsługiwać błędy, należy używać bloków try-catch w orkiestratorze. W przypadku błędów przejściowych należy skonfigurować automatyczne ponowienia z narastającym opóźnieniem za pomocą callActivityWithRetry, określając maksymalną liczbę prób, początkowy odstęp między ponowieniami i współczynnik narastania opóźnienia. Jest to zalecany wzorzec dla aktywności wywołujących zewnętrzne interfejsy API lub bazy danych.

// Orchestrator: retry an activity with exponential backoff
module.exports = df.orchestrator(function* (context) {
  const retryOptions = new df.RetryOptions(
    5000,  // firstRetryIntervalInMilliseconds
    3      // maxNumberOfAttempts
  );
  retryOptions.backoffCoefficient = 2; // 5s, 10s, 20s

  try {
    const result = yield context.df.callActivityWithRetry(
      'CallExternalAPI',
      retryOptions,
      context.df.getInput()
    );
    return result;
  } catch (e) {
    yield context.df.callActivity('SendFailureAlert', e.message);
    throw e;
  }
});

Trwałe encje

Trwałe encje (funkcje encji) implementują niewielkie fragmenty trwałego stanu dostępne na podstawie tożsamości — podobnie jak wirtualni aktorzy. Encja ma identyfikator i stan, który jest zachowywany pomiędzy wywołaniami. Operacje na encji są wywoływane z orkiestratora lub klienta, a encja przetwarza je pojedynczo (szeregowo). Typowe zastosowania obejmują liczniki, automaty stanów zatwierdzania, ograniczniki szybkości i koszyki zakupowe — czyli wszystkie scenariusze wymagające trwałego, aktualizowalnego stanu bez użycia bazy danych.

// Counter entity function
const df = require('durable-functions');
module.exports = df.entity(function (context) {
  let count = context.df.getState(() => 0);
  const operation = context.df.operationName;

  if (operation === 'add') count += context.df.getInput();
  if (operation === 'reset') count = 0;
  if (operation === 'get') context.df.return(count);

  context.df.setState(count);
});

// From orchestrator, increment counter entity
// const entityId = new df.EntityId('Counter', 'myCounter');
// yield context.df.callEntity(entityId, 'add', 1);

Szybki test

Sprawdź swoją znajomość zagadnień Microsoft Azure Fundamentals (AZ-900) omówionych w tej lekcji.

Podsumowanie lekcji

W tej lekcji poznali Państwo: Durable Functions umożliwia tworzenie stanowych, długotrwałych przepływów pracy dzięki zapisywaniu stanu orkiestratora w Azure Storage, a najważniejsze wzorce obejmują łańcuchowy, fan-out/fan-in, monitorowania i interakcji z użytkownikiem; ponadto orkiestratory muszą być deterministyczne — wszystkie operacje wejścia-wyjścia i wywołania niedeterministyczne muszą być realizowane za pośrednictwem funkcji aktywności. W następnej części omówimy Azure Logic Apps.

Bezpłatny start

Ucz się Cloud & IT Cert Prep dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
150
Lekcje
600

Często zadawane pytania

Czy lekcja „Durable Functions dla przepływów pracy ze stanem” jest bezpłatna?

Tak — pełny tekst „Durable Functions dla przepływów pracy ze stanem” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Cloud & IT Cert Prep, przejdź na CoddyKit PRO. Kurs Cloud & IT Cert Prep zawiera 4 lekcji w sumie.

Co nauczysz się w „Durable Functions dla przepływów pracy ze stanem”?

Orkiestruj długotrwałe przepływy pracy za pomocą wzorców orkiestratora Durable Functions (fan-out/fan-in, chaining, monitor) oraz poznaj sposób tworzenia punktów kontrolnych stanu. Ćwiczysz Cloud & IT Cert Prep z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Cloud & IT Cert Prep?

Nie wymagamy żadnego doświadczenia. Cloud & IT Cert Prep w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Durable Functions dla przepływów pracy ze stanem”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Cloud & IT Cert Prep?

Tak. Każda lekcja Cloud & IT Cert Prep zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Wyzwalacze i powiązania Azure Functions
  2. Durable Functions dla przepływów pracy ze stanem
  3. Azure Logic Apps
  4. Event Grid i architektura sterowana zdarzeniami
← Powrót do Cloud & IT Cert Prep