다음을 통해 공유


Durable Functions의 버전 관리 문제 및 접근 방식(Azure Functions)

애플리케이션의 수명 동안 함수를 추가, 제거 및 변경하는 것은 불가피합니다. Durable Functions를 사용하면 이전에는 불가능했던 방식으로 함수를 함께 연결할 수 있으며, 이 체인은 버전 관리 방법을 처리하는 방법에 영향을 줍니다.

중대한 변경 내용의 형식

알아야 할 주요 변경 내용의 몇 가지 예가 있습니다. 이 문서에서는 가장 일반적인 항목에 대해 설명합니다. 이 모든 항목의 주요 테마는 새 함수 오케스트레이션과 기존 함수 오케스트레이션 모두 함수 코드 변경의 영향을 받습니다.

활동 또는 엔터티 함수 시그니처 변경

서명 변경은 함수의 이름, 입력 또는 출력의 변경 사항을 나타냅니다. 이러한 종류의 변경이 활동 또는 엔터티 함수에 적용된 경우 해당 함수에 의존하는 오케스트레이터 함수가 중단됩니다. 형식이 안전한 언어의 경우 특히 그렇습니다. 이 변경을 수용하도록 오케스트레이터 함수를 업데이트하는 경우 기존 진행 중인 인스턴스를 중단시킬 수 있습니다.

예를 들어 다음 오케스트레이터 함수가 있다고 가정합니다.

[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    bool result = await context.CallActivityAsync<bool>("Foo");
    await context.CallActivityAsync("Bar", result);
}

이 간단한 함수는 Foo 의 결과를 가져와 Bar에 전달합니다. 더 다양한 결과 값을 지원하기 위해 Foo 의 반환 값을 부울에서 문자열로 변경해야 한다고 가정해 보겠습니다. 결과는 다음과 같습니다.

[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    string result = await context.CallActivityAsync<string>("Foo");
    await context.CallActivityAsync("Bar", result);
}

이 변경 사항은 오케스트레이터 함수의 모든 새 인스턴스에는 잘 작동하지만, 진행 중인 인스턴스에 문제를 일으킬 수 있습니다. 예를 들어 오케스트레이션 인스턴스가 Foo라는 함수를 호출하고 부울 값을 반환하고 검사점을 설정하는 경우를 고려합니다. 이 시점에서 시그니처 변경이 배포되면 검사점이 설정된 인스턴스는 다시 시작되고 Foo에 대한 호출을 재생할 때 즉시 실패합니다. 이 오류는 기록 테이블의 결과가 부울 값이지만 새 코드가 문자열 값으로 역직렬화하려고 시도하여 형식이 안전한 언어에 대해 예기치 않은 동작 또는 런타임 예외가 발생하므로 발생합니다.

이 예제는 함수 서명 변경으로 기존 인스턴스가 중단되는 여러 가지 방법 중 하나일 뿐입니다. 일반적으로 오케스트레이터가 함수를 호출하는 방식을 변경해야 하는 경우 변경에 문제가 있을 수 있습니다.

오케스트레이터 논리 변경

다른 버전 관리 문제 클래스는 진행 중인 인스턴스의 실행 경로를 변경하는 방식으로 오케스트레이터 함수 코드를 변경하여 발생합니다.

다음 오케스트레이터 함수를 고려합니다.

[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    bool result = await context.CallActivityAsync<bool>("Foo");
    await context.CallActivityAsync("Bar", result);
}

이제 두 기존 함수 호출 사이에 새 함수 호출을 추가하도록 변경하려는 경우를 가정해 보겠습니다.

[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    bool result = await context.CallActivityAsync<bool>("Foo");
    if (result)
    {
        await context.CallActivityAsync("SendNotification");
    }

    await context.CallActivityAsync("Bar", result);
}

이 변경으로 FooBar 간에 SendNotification에 대한 새 함수 호출이 추가됩니다. 서명 변경은 없습니다. 기존 인스턴스가 Bar 호출에서 다시 시작될 때 문제가 발생합니다. 재생 중에 Foo 에 대한 원래 호출이 반환 true된 경우 오케스트레이터 재생은 실행 기록에 없는 SendNotification을 호출합니다. 런타임은 이 불일치를 감지하고 Bar에 대한 호출을 예상했을 때 SendNotification에 대한 호출을 발견했기 때문에 비결정 오케스트레이션을 발생시킵니다. 지속성 타이머 만들기, 외부 이벤트 대기, 하위 오케스트레이션 호출 등과 같은 다른 지속성 작업에 API 호출을 추가할 때 동일한 유형의 문제가 발생할 수 있습니다.

완화 전략

버전 관리 문제를 처리하기 위한 몇 가지 전략은 다음과 같습니다.

  • 아무 작업도 수행하지 않음(권장하지 않음)
  • 오케스트레이션 버전 관리(대부분의 경우 권장)
  • 모든 기내 인스턴스 중지
  • 독립적 배치

아무 것도 수행하지 않음

버전 관리의 단순한 접근 방식은 아무 것도 하지 않고 진행 중인 오케스트레이션 인스턴스의 실패를 방치하는 것입니다. 변경 유형에 따라 다음과 같은 유형의 오류가 발생할 수 있습니다.

  • 비결정적 오케스트레이션 오류로 오케스트레이션이 실패할 수 있습니다.
  • 오케스트레이션이 무기한 중단되어 Running 상태를 보고할 수 있습니다.
  • 함수가 제거되면 함수를 호출하려고 시도하는 모든 함수가 오류와 함께 실패할 수 있습니다.
  • 함수가 실행되도록 예약된 후 제거되면 앱에서 지속성 작업 프레임워크 엔진에서 낮은 수준의 런타임 오류가 발생하여 성능이 저하될 수 있습니다.

이러한 잠재적 오류로 인해 "아무 작업도 수행하지 않음" 전략은 권장되지 않습니다.

오케스트레이션 버전 관리

비고

오케스트레이션 버전 관리가 현재 공개 미리 보기로 제공됩니다.

오케스트레이션 버전 관리 기능을 사용하면 충돌 및 비결정적 문제 없이 여러 버전의 오케스트레이션이 공존하고 동시에 실행될 수 있으므로 수동 개입 없이 진행 중인 오케스트레이션 인스턴스가 완료되도록 하면서 업데이트를 배포할 수 있습니다.

오케스트레이션 버전 관리:

  • 각 오케스트레이션 인스턴스는 생성될 때 영구적으로 연결된 버전을 가져옵니다.
  • 오케스트레이터 함수는 그에 따라 해당 버전 및 분기 실행을 검사할 수 있습니다.
  • 최신 오케스트레이터 함수 버전을 실행하는 작업자는 이전 버전에서 만든 오케스트레이션 인스턴스를 계속 실행할 수 있습니다.
  • 런타임을 사용하면 이전 오케스트레이터 함수 버전을 실행하는 작업자가 최신 버전의 오케스트레이션을 실행할 수 없습니다.

이 전략은 가동 중지 시간 없는 배포를 유지하면서도 호환성이 손상되는 변경을 지원해야 하는 애플리케이션에 권장됩니다.

자세한 구성 및 구현 지침은 Durable Functions의 오케스트레이션 버전 관리를 참조하세요.

모든 기내 인스턴스 중지

또 다른 옵션은 모든 기내 인스턴스를 중지하는 것입니다. Durable Functions에 대한 기본 Azure Storage 공급자를 사용하는 경우 내부 control-queueworkitem-queue 큐의 내용을 지우면 모든 인스턴스를 중지할 수 있습니다. 또는 함수 앱을 중지하고, 이러한 큐를 삭제하고, 앱을 다시 시작할 수 있습니다. 앱이 다시 시작되면 큐가 자동으로 다시 생성됩니다. 이전 오케스트레이션 인스턴스는 무기한으로 "실행 중" 상태로 유지될 수 있지만 실패 메시지로 로그를 어지럽히거나 앱에 해를 끼치지 않습니다. 이 접근 방식은 로컬 개발을 포함하여 신속한 프로토타입 개발에 이상적입니다.

비고

이 방법을 사용하려면 기본 스토리지 리소스에 직접 액세스해야 하며 Durable Functions에서 지원하는 모든 스토리지 공급자에게는 적합하지 않을 수 있습니다.

독립적 배치

호환성이 손상되는 변경 내용이 안전하게 배포되도록 하는 가장 실패 방지 방법은 이전 버전과 함께 배포하는 것입니다. 이 작업은 다음 기술 중 어느 것을 사용하여 수행할 수 있습니다.

  • 모든 업데이트를 완전히 새로운 함수로 배포하고, 기존 함수는 그대로 as-is에 두십시오. 일반적으로 새 함수 버전의 호출자를 재귀적으로 업데이트하는 복잡성 때문에 권장되지 않습니다.
  • 모든 업데이트를 다른 스토리지 계정으로 새 함수 앱으로 배포합니다.
  • 동일한 스토리지 계정을 사용하지만 업데이트된 작업 허브 이름을 사용하여 함수 앱의 새 복사본을 배포합니다. 그러면 새 버전의 앱에서 사용할 수 있는 새 스토리지 아티팩트가 만들어집니다. 이전 버전의 앱은 이전 스토리지 아티팩트 집합을 사용하여 계속 실행됩니다.

병렬 배포는 새 버전의 함수 앱을 배포하는 데 권장되는 기술입니다.

비고

병렬 배포 전략에 대한 이 지침은 Azure Storage 관련 용어를 사용하지만 일반적으로 지원되는 모든 Durable Functions 스토리지 공급자에 적용됩니다.

배포 슬롯

Azure Functions 또는 Azure App Service에서 병렬 배포를 수행하는 경우 새 버전의 함수 앱을 새 배포 슬롯에 배포하는 것이 좋습니다. 배포 슬롯을 사용하면 함수 앱의 여러 복사본을 활성 프로덕션 슬롯으로 하나만 함께 실행할 수 있습니다. 새 오케스트레이션 논리를 기존 인프라에 노출할 준비가 되면 새 버전을 프로덕션 슬롯으로 교환하는 것만큼 간단할 수 있습니다.

비고

이 전략은 오케스트레이터 함수에 HTTP 및 웹후크 트리거를 사용하는 경우에 가장 적합합니다. 큐 또는 Event Hubs와 같은 비 HTTP 트리거의 경우 트리거 정의는 교환 작업의 일부로 업데이트되는 앱 설정에서 파생 되어야 합니다.

다음 단계