오케스트레이터 함수 코드 제약 조건

Durable Functions는 상태 저장 앱을 빌드하도록 지원하는 Azure Functions의 확장입니다. 오케스트레이터 함수를 사용하여 함수 앱 내에서 다른 지속성 함수의 실행을 오케스트레이션할 수 있습니다. 오케스트레이터 함수는 상태를 저장하고, 신뢰할 수 있으며, 장기 실행될 수 있습니다.

오케스트레이터 코드 제약 조건

오케스트레이터 함수는 이벤트 소싱을 사용하여 신뢰할 수 있는 실행을 보장하고 로컬 변수 상태를 유지합니다. 오케스트레이터 코드의 재생 동작은 오케스트레이터 함수에 작성될 수 있는 코드 형식에 대한 제약 조건을 만듭니다. 예를 들어 오케스트레이터 함수는 결정적이어야 합니다. 오케스트레이터 함수는 여러 번 재생되며 매번 동일한 결과를 생성해야 합니다.

결정적 API 사용

이 섹션에서는 결정적 코드를 보장하는 데 도움이 되는 몇 가지 간단한 지침을 제공합니다.

오케스트레이터 함수는 대상 언어의 모든 API를 호출할 수 있습니다. 그러나 오케스트레이터 함수는 결정적 API만 호출해야 합니다. 결정적 API는 호출 시기 또는 빈도에 관계없이 동일한 입력에서 항상 동일한 값을 반환하는 API입니다.

다음 섹션에서는 결정적이지 않으므로 피해야 하는 API 및 패턴에 대한 지침을 제공합니다. 이러한 제한 사항은 오케스트레이터 함수에만 적용됩니다. 다른 함수 유형에는 이러한 제한 사항이 없습니다.

참고 항목

몇 가지 유형의 코드 제약 조건이 아래에 설명되어 있습니다. 이 목록은 아쉽게도 포괄적이지 않으며 일부 사용 사례를 다루지 않을 수 있습니다. 오케스트레이터 코드를 작성할 때 고려해야 할 가장 중요한 사항은 사용하는 API가 결정적인지 여부입니다. 이러한 방식으로 생각하는 데 익숙해지면 이 문서화된 목록을 참조하지 않고도 사용하기에 안전한 API와 그렇지 않은 API를 쉽게 이해할 수 있습니다.

날짜 및 시간

현재 날짜 또는 시간을 반환하는 API는 비결정적이며 오케스트레이터 함수에서 사용하면 안 됩니다. 이는 각 오케스트레이터 함수 재생에서 다른 값을 생성하기 때문입니다. 대신 재생 간에 일관성을 유지하는 현재 날짜 또는 시간을 가져오기 위해 Durable Functions에 해당하는 API를 사용해야 합니다.

DateTime.Now, DateTime.UtcNow 또는 이에 해당하는 API를 사용하여 현재 시간을 가져오지 않습니다. Stopwatch와 같은 클래스도 피해야 합니다. .NET 프로세스 내 오케스트레이터 함수의 경우 IDurableOrchestrationContext.CurrentUtcDateTime 속성을 사용하여 현재 시간을 가져옵니다. .NET 격리 오케스트레이터 함수의 경우 TaskOrchestrationContext.CurrentDateTimeUtc 속성을 사용하여 현재 시간을 가져옵니다.

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

GUID 및 UUID

임의의 GUID 또는 UUID를 반환하는 API는 각 재생마다 다른 값이 생성되기 때문에 비결정적입니다. 사용하는 언어에 따라 결정적 GUID 또는 UUID를 생성하는 기본 제공 API를 사용할 수 있습니다. 그렇지 않으면 작업 함수를 사용하여 임의로 생성된 GUID 또는 UUID를 반환합니다.

Guid.NewGuid()와 같은 API를 사용하여 임의의 GUID를 생성하지 않습니다. 대신 컨텍스트 개체의 NewGuid() API를 사용하여 오케스트레이터 재생에 안전한 임의의 GUID를 생성하세요.

Guid randomGuid = context.NewGuid();

참고 항목

오케스트레이션 컨텍스트 API를 사용하여 생성된 GUID는 유형 5 UUID입니다.

난수

작업 함수를 사용하여 난수를 오케스트레이터 함수에 반환합니다. 작업 함수의 반환 값은 오케스트레이션 기록에 저장되므로 항상 재생하기에 안전합니다.

또는 오케스트레이터 함수에서 고정된 시드 값이 있는 난수 생성기를 직접 사용할 수 있습니다. 각 오케스트레이션 재생에 대해 동일한 숫자 시퀀스가 ​​생성되는 경우 이 방법이 안전합니다.

바인딩

오케스트레이터 함수는 오케스트레이션 클라이언트엔터티 클라이언트 바인딩도 포함하여 바인딩을 사용하지 않아야 합니다. 항상 클라이언트 또는 작업 함수 내에서 입력 및 출력 바인딩을 사용합니다. 이는 오케스트레이터 함수가 여러 번 재생되어 외부 시스템에서 비결정적이고 중복된 I/O가 발생할 수 있으므로 중요합니다.

정적 변수

시간이 지남에 따라 값이 변경되어 비결정적 런타임 동작이 발생할 수 있으므로 오케스트레이터 함수에서 정적 변수를 사용하지 않습니다. 대신 상수를 사용하거나 정적 변수가 작업 함수에만 사용되도록 제한합니다.

참고 항목

여러 함수 실행에서 정적 상태가 유지된다고 보장하지 않으므로 오케스트레이터 함수 외부에서도 Azure Functions의 정적 변수를 사용하는 것은 다양한 이유로 문제가 될 수 있습니다. 작업 또는 엔터티 함수의 최상의 메모리 내 캐싱과 같은 매우 구체적인 사용 사례를 제외하고는 정적 변수를 피해야 합니다.

환경 변수

오케스트레이터 함수에서 환경 변수를 사용하지 않습니다. 해당 값은 시간이 지남에 따라 변경될 수 있으므로 비결정적 런타임 동작이 발생합니다. 환경 변수에 정의된 구성이 오케스트레이터 함수에 필요한 경우 구성 값을 작업 함수의 입력 또는 반환 값으로 오케스트레이터 함수에 전달해야 합니다.

네트워크 및 HTTP

작업 함수를 사용하여 아웃바운드 네트워크 호출을 수행합니다. 오케스트레이터 함수에서 HTTP 호출을 수행해야 하는 경우 지속성 HTTP API를 사용할 수도 있습니다.

스레드 차단 API

"절전 모드"와 같은 차단 API는 오케스트레이터 함수에 대한 성능 및 확장 문제를 유발할 수 있으므로 피해야 합니다. Azure Functions 사용량 요금제에서는 불필요한 실행 시간 요금이 발생할 수도 있습니다. 블로킹 API를 사용할 수 있는 경우에도 대체 방법을 사용하세요. 예를 들어 지속성 타이머를 사용하여 재생하기에 안전하고 오케스트레이터 함수의 실행 시간에 포함되지 않는 지연을 만듭니다.

비동기 API

오케스트레이터 코드는 오케스트레이션 트리거의 컨텍스트 개체에서 정의한 작업을 제외하고는 어떤 비동기 작업도 시작하지 않아야 합니다. 예를 들어 .NET에서 Task.Run, Task.DelayHttpClient.SendAsync를 사용하지 않거나 JavaScript에서 setTimeoutsetInterval을 사용하지 않습니다. 오케스트레이터 함수는 작업 함수 예약과 같은 지속성 SDK API를 사용하여 비동기 작업만 예약해야 합니다. 다른 유형의 비동기 호출은 작업 함수 내에서 수행해야 합니다.

비동기 JavaScript 함수

항상 JavaScript 오케스트레이터 함수를 동기 생성기 함수로 선언합니다. Node.js 런타임은 결정적인 비동기 함수를 보장하지 않으므로 JavaScript 오케스트레이터 함수를 async로 선언하지 않아야 합니다.

Python 코루틴

Python 오케스트레이터 함수를 코루틴으로 선언하지 않아야 합니다. 즉, 코루틴 의미 체계가 Durable Functions 재생 모델과 일치하지 않으므로 async 키워드를 사용하여 Python 오케스트레이터 함수를 선언하지 않습니다. Python 오케스트레이터 함수는 항상 생성기로 선언해야 합니다. 즉, context API에서 await 대신 yield를 사용해야 합니다.

.NET 스레딩 API

Durable Task Framework는 단일 스레드에서 오케스트레이터 코드를 실행하며 다른 모든 스레드와 상호 작용할 수 없습니다. 작업자 풀 스레드에서 비동기 연속 작업을 실행하면 오케스트레이션의 실행으로 인해 비결정적 실행 또는 교착 상태가 발생할 수 있습니다. 이러한 이유로 오케스트레이터 함수는 스레드 API를 거의 사용하지 않아야 합니다. 예를 들어 오케스트레이터 함수에서 ConfigureAwait(continueOnCapturedContext: false)를 사용하지 않습니다. 이렇게 하면 오케스트레이터 함수의 원래 SynchronizationContext에서 작업 연속이 실행됩니다.

참고 항목

지속성 작업 프레임워크는 오케스트레이터 함수에서 비 오케스트레이터 스레드를 실수로 사용하는 것을 검색하려고 시도합니다. 위반을 발견하면 프레임워크에서 NonDeterministicOrchestrationException 예외를 throw합니다. 그러나 이 검색 동작이 모든 위반을 catch하지는 않으므로 여기에 의존해서는 안 됩니다.

버전 관리

지속성 오케스트레이션은 수일, 수개월, 수년 동안 실행되거나 심지어 계속 실행될 수도 있습니다. 완료되지 않은 오케스트레이션에 영향을 주는 Durable Functions 앱에 대한 모든 코드 업데이트는 오케스트레이션의 재생 동작을 중단시킬 수 있습니다. 따라서 코드를 업데이트할 때 신중하게 계획하는 것이 중요합니다. 코드 버전 관리 방법에 대한 자세한 설명은 버전 관리 문서를 참조하세요.

지속성 작업

참고 항목

이 섹션에서는 지속성 작업 프레임워크의 내부 구현에 대해 자세히 설명합니다. 이 정보를 알지 못해도 지속성 함수를 사용할 수 있습니다. 여기서는 재생 동작을 이해하는 데에만 도움이 됩니다.

오케스트레이터 함수에서 안전하게 기다릴 수 있는 태스크를 종종 지속성 태스크라고 합니다. Durable Task Framework는 이러한 태스크를 만들고 관리합니다. 예로 .NET 오케스트레이터 함수에서 CallActivityAsync, WaitForExternalEvent, CreateTimer를 반환하는 작업을 들 수 있습니다.

이러한 지속성 태스크는 .NET에서 TaskCompletionSource 개체의 목록을 사용하여 내부적으로 관리됩니다. 이러한 태스크는 재생하는 동안 오케스트레이터 코드 실행의 일부로 만들어집니다. 디스패처에서 해당 기록 이벤트를 열거하면 완료됩니다.

모든 기록이 재생될 때까지 단일 스레드를 사용하여 태스크가 동기적으로 수행됩니다. 기록 재생이 끝날 때까지 종료되지 않은 지속성 작업에는 적절한 조치가 수행됩니다. 예를 들면 메시지를 큐에 넣어 작업 함수를 호출할 수도 있습니다.

이 섹션의 런타임 동작에 대한 설명은 오케스트레이터 함수가 비지속성 태스크에서 await 또는 yield를 사용할 수 없는 이유를 이해하는 데 도움이 됩니다. 두 가지 이유는 다음과 같습니다. 디스패처 스레드는 태스크가 완료될 때까지 기다릴 수 없으며, 해당 태스크의 콜백은 오케스트레이터 함수의 추적 상태를 손상시킬 수 있습니다. 이러한 위반을 감지하는 데 도움이 되는 몇 가지 런타임 검사가 준비되어 있습니다.

Durable Task Framework에서 오케스트레이터 함수를 실행하는 방법에 대한 자세한 내용은 GitHub의 Durable Task 소스 코드를 참조하세요. 특히 TaskOrchestrationExecutor.csTaskOrchestrationContext.cs를 참조하세요.

다음 단계