다음을 통해 공유


오케스트레이션 버전 관리(미리 보기)

오케스트레이션 업그레이드 및 다운그레이드는 지속성 오케스트레이션 시스템을 사용할 때 중요한 고려 사항입니다. 오케스트레이션이 중단되고 나중에 다시 시작된 경우(예: 호스트 업데이트 중) Durable Task Scheduler는 오케스트레이션의 이벤트를 재생하여 다음 단계를 수행하기 전에 이전 단계가 모두 성공적으로 실행되었는지 확인합니다. 이 작업은 지속성 실행 패러다임의 핵심 약속 중 하나인 안정성을 보장합니다.

배포 간에 오케스트레이션이 변경되면 수행하는 단계가 더 이상 동일하지 않을 수 있습니다. 이 경우 시스템은 오케스트레이션을 계속하도록 허용하는 대신 NonDeterministicError 오류를 발생시킵니다.

오케스트레이션 버전 관리에서는 비결정과 관련된 문제를 방지하여 새 오케스트레이션 또는 이전 오케스트레이션을 원활하게 작업할 수 있습니다. 지속성 작업 스케줄러에는 별도로 또는 함께 사용할 수 있는 두 가지 버전의 버전 관리가 있습니다.

중요합니다

현재 지속성 작업 SDK는 JavaScript 및 PowerShell에 사용할 수 없습니다.

중요합니다

현재 지속성 작업 SDK는 JavaScript 및 PowerShell에 사용할 수 없습니다.

클라이언트/컨텍스트 기반 조건부 버전 관리

오케스트레이션에 버전이 있도록 하려면 먼저 클라이언트에서 설정해야 합니다.

.NET SDK는 표준 호스트 작성기 확장을 사용합니다.

비고

v1.9.0 이후 .NET SDK(Microsoft.DurableTask.Client.AzureManaged)에서 사용할 수 있습니다.

builder.Services.AddDurableTaskClient(builder =>
{
    builder.UseDurableTaskScheduler(connectionString);
    builder.UseDefaultVersion("1.0.0");
});

비고

v1.6.0 이후 Java SDK(com.microsoft:durabletask-client)에서 사용할 수 있습니다.

public DurableTaskClient durableTaskClient(DurableTaskProperties properties) {
    // Create client using Azure-managed extensions
    return DurableTaskSchedulerClientExtensions.createClientBuilder(properties.getConnectionString())
        .defaultVersion("1.0")
        .build();
}
 c = DurableTaskSchedulerClient(host_address=endpoint, secure_channel=secure_channel,
                                   taskhub=taskhub_name, token_credential=credential,
                                   default_version="1.0.0")

클라이언트에 버전을 추가하면 이 호스트에서 시작한 모든 오케스트레이션에서 버전을 1.0.0사용합니다. 버전은 간단한 문자열이며 모든 값을 허용합니다. 그러나 SDK는 이를 .NET의 System.Version로 변환하려고 합니다.

  • 변환이 가능한 경우 해당 라이브러리가 비교에 사용됩니다.
  • 그렇지 않은 경우 간단한 문자열 비교가 사용됩니다.

또한 클라이언트에서 버전을 제공하면 조건문에서 TaskOrchestrationContext버전을 사용할 수 있습니다. 최신 오케스트레이션 버전에 적절한 버전 게이팅이 있는 한 이전 및 새 오케스트레이션 버전은 모두 동일한 호스트에서 함께 실행할 수 있습니다.

Example:

[DurableTask]
class HelloCities : TaskOrchestrator<string, List<string>>
{
    private readonly string[] Cities = ["Seattle", "Amsterdam", "Hyderabad", "Kuala Lumpur", "Shanghai", "Tokyo"];

    public override async Task<List<string>> RunAsync(TaskOrchestrationContext context, string input)
    {
        List<string> results = [];
        foreach (var city in Cities)
        {
            results.Add(await context.CallSayHelloAsync($"{city} v{context.Version}"));
            if (context.CompareVersionTo("2.0.0") >= 0)
            {
                results.Add(await context.CallSayGoodbyeAsync($"{city} v{context.Version}"));
            }
        }

        Console.WriteLine("HelloCities orchestration completed.");
        return results;
    }
}

클라이언트에 버전을 추가하면 이 클라이언트에서 시작한 모든 오케스트레이션에서 버전을 1.0.0사용합니다. 버전은 간단한 문자열이며 모든 값을 허용합니다.

또한 클라이언트에서 버전을 제공하면 해당 버전을 사용할 수 있습니다 TaskOrchestration. 즉, 조건문에서 버전을 사용할 수 있습니다. 최신 오케스트레이션 버전에 적절한 버전 게이팅이 있는 한 이전 오케스트레이션 버전과 새 오케스트레이션 버전은 모두 동일한 클라이언트에서 함께 실행할 수 있습니다.

Example:

public TaskOrchestration create() {
    return ctx -> {
        List<String> results = new ArrayList<>();
        for (String city : new String[]{ "Seattle", "Amsterdam", "Hyderabad", "Kuala Lumpur", "Shanghai", "Tokyo" }) {
            results.add(ctx.callActivity("SayHello", city, String.class).await());
            if (VersionUtils.compareVersions(ctx.getVersion(), "2.0.0") >= 0) {
                // Simulate a delay for newer versions
                results.add(ctx.callActivity("SayGoodbye", city, String.class).await());
            }
        }
        ctx.complete(results);
    };
}

클라이언트에 버전을 추가하면 이 클라이언트에서 시작한 모든 오케스트레이션에서 버전을 1.0.0사용합니다. 버전은 packaging.version를 사용하여 구문 분석된 간단한 문자열로, 시맨틱 버저닝 비교를 지원하고 모든 값을 허용합니다.

또한 클라이언트에서 버전을 제공하면 조건문에서 task.OrchestrationContext버전을 사용할 수 있습니다. 최신 오케스트레이션 버전에 적절한 버전 게이팅이 있는 한 이전 오케스트레이션 버전과 새 오케스트레이션 버전은 모두 동일한 클라이언트에서 함께 실행할 수 있습니다.

Example:

def orchestrator(ctx: task.OrchestrationContext, _):
    if ctx.version == "1.0.0":
        # For version 1.0.0, we use the original logic
        result: int = yield ctx.call_activity(activity_v1, input="input for v1")
    elif ctx.version == "2.0.0":
        # For version 2.0.0, we use the updated logic
        result: int = yield ctx.call_activity(activity_v2, input="input for v2")
    else:
        raise ValueError(f"Unsupported version: {ctx.version}")
    return {
        'result': result,
    }

이 예제에서는 SayGoodbye 활동을 HelloCities 오케스트레이션에 추가했습니다. 이 활동은 오케스트레이션 버전 2.0.0 이상에 대해서만 호출됩니다. 간단한 조건문을 사용하면 버전보다 2.0.0 작은 오케스트레이션이 계속 작동하며 새 오케스트레이션에는 새 작업이 포함됩니다.

클라이언트 버전 관리 사용 시기

클라이언트 버전 관리에서는 오케스트레이션의 버전을 관리하는 가장 간단한 메커니즘을 제공하지만 버전과 상호 작용하는 것은 프로그래밍 집약적일 수 있습니다. 다음과 같은 경우 클라이언트 버전 관리 사용

  • 모든 버전에서 표준 버전을 사용하거나
  • 특정 버전에 대한 사용자 지정 논리가 필요합니다.

작업자 기반 버전 관리

오케스트레이션은 버전을 설정하기 위해 클라이언트 버전이 여전히 필요하지만 작업자 기반 버전 관리 방법을 사용하면 오케스트레이션에서 조건부를 방지할 수 있습니다. 작업자는 실행을 시작하기 전에 다른 버전의 오케스트레이션에 대해 작업하는 방법을 선택합니다.

작업자 버전 관리에서는 다음 필드를 설정해야 합니다.

  1. 작업자 버전입니다.

  2. 작업자가 시작한 하위 오케스트레이션에 적용되는 기본 버전입니다.

  3. 작업자가 오케스트레이션의 버전과 일치시키는 데 사용하는 전략입니다.

    이름 설명
    없음 작업이 처리될 때 버전이 고려되지 않습니다.
    Strict 오케스트레이션의 버전과 작업자가 정확히 일치해야 합니다.
    현재값_또는_이전값 오케스트레이션의 버전은 작업자의 버전보다 같거나 낮아야 합니다.
  4. 버전이 일치 전략을 충족하지 않는 경우 작업자가 사용하는 전략입니다.

    이름 설명
    거절하다 워크러버가 오케스트레이션을 거절하지만 작업 대기열에 남아 나중에 다시 시도됩니다
    실패 오케스트레이션이 실패하고 작업 큐에서 제거됨

클라이언트 버전 관리와 마찬가지로 표준 호스트 작성기 패턴을 통해 이러한 필드를 설정할 수 있습니다.

비고

v1.9.0 이후 .NET SDK(Microsoft.DurableTask.Worker.AzureManaged)에서 사용할 수 있습니다.

builder.Services.AddDurableTaskWorker(builder =>
{
    builder.AddTasks(r => r.AddAllGeneratedTasks());
    builder.UseDurableTaskScheduler(connectionString);
    builder.UseVersioning(new DurableTaskWorkerOptions.VersioningOptions
    {
        Version = "1.0.0",
        DefaultVersion = "1.0.0",
        MatchStrategy = DurableTaskWorkerOptions.VersionMatchStrategy.Strict,
        FailureStrategy = DurableTaskWorkerOptions.VersionFailureStrategy.Reject,
    });
});

비고

v1.6.0 이후 Java SDK(com.microsoft:durabletask-client)에서 사용할 수 있습니다.

private static DurableTaskGrpcWorker createTaskHubServer() {
    DurableTaskGrpcWorkerBuilder builder = new DurableTaskGrpcWorkerBuilder();
    builder.useVersioning(new DurableTaskGrpcWorkerVersioningOptions(
            "1.0",
            "1.0",
            DurableTaskGrpcWorkerVersioningOptions.VersionMatchStrategy.CURRENTOROLDER,
            DurableTaskGrpcWorkerVersioningOptions.VersionFailureStrategy.REJECT));

    // Orchestrations can be defined inline as anonymous classes or as concrete classes
    builder.addOrchestration(new TaskOrchestrationFactory() {
        @Override
        public String getName() { return "HelloCities"; }

        @Override
        public TaskOrchestration create() {
            return ctx -> {
                List<String> results = new ArrayList<>();
                for (String city : new String[]{ "Seattle", "Amsterdam", "Hyderabad", "Kuala Lumpur", "Shanghai", "Tokyo" }) {
                    results.add(ctx.callActivity("SayHello", city, String.class).await());
                }
                ctx.complete(results);
            };
        }
    });

    // Activities can be defined inline as anonymous classes or as concrete classes
    builder.addActivity(new TaskActivityFactory() {
        @Override
        public String getName() { return "SayHello"; }

        @Override
        public TaskActivity create() {
            return ctx -> {
                String input = ctx.getInput(String.class);
                return "Hello, " + input + "!";
            };
        }
    });

    return builder.build();
}
with DurableTaskSchedulerWorker(host_address=endpoint, secure_channel=secure_channel,
                                taskhub=taskhub_name, token_credential=credential) as w:
    # This worker is versioned for v2, as the orchestrator code has already been updated
    # CURRENT_OR_OLDER allows this worker to process orchestrations versioned below 2.0.0 - e.g. 1.0.0
    w.use_versioning(worker.VersioningOptions(
        version="2.0.0",
        default_version="2.0.0",
        match_strategy=worker.VersionMatchStrategy.CURRENT_OR_OLDER,
        failure_strategy=worker.VersionFailureStrategy.FAIL
    ))
    w.add_orchestrator(orchestrator)
    w.add_activity(activity_v1)
    w.add_activity(activity_v2)
    w.start()

실패 전략

거부

원하는 동작이 오케스트레이션이 나중에 또는 다른 작업자에서 재시도하는 것일 때 Reject 실패 전략을 사용하세요. Reject 오류 발생 시:

  1. 오케스트레이션이 거부되어 작업 대기열로 반환됩니다.
  2. 오케스트레이션이 대기열에서 제거되었습니다.
  3. 대기열에서 제거된 오케스트레이션은 다른 작업자나 동일한 작업자에게 다시 할당될 수 있습니다.

오케스트레이션을 처리할 수 있는 작업자를 사용할 수 있게 될 때까지 프로세스가 반복됩니다. 이 전략은 오케스트레이션이 업데이트되는 배포를 원활하게 처리합니다. 배포가 진행됨에 따라 오케스트레이션을 처리할 수 없는 작업자는 이를 거부하고 처리할 수 있는 작업자는 이를 처리합니다.

혼합 작업자 및 오케스트레이션 버전을 사용하는 기능을 사용하면 청록색 배포와 같은 시나리오를 사용할 수 있습니다.

Fail

다른 버전이 예상되지 않는 경우 Fail 실패 전략을 사용합니다. 이 경우 새 버전은 변칙이며 작업자가 작업을 시도하지 않아야 합니다. 지속형 작업 스케줄러가 오케스트레이션을 실패하여 종단 상태로 전환됩니다.

작업자 버전 관리 사용 시기

알 수 없거나 지원되지 않는 오케스트레이션 버전을 전혀 실행해서는 안 되는 시나리오에서 작업자 버전 관리를 사용합니다. 작업자에 버전 처리 코드를 배치하는 대신 작업자 버전 관리를 통해 오케스트레이션 실행이 중지됩니다. 이 메서드를 사용하면 더 간단한 오케스트레이션 코드를 사용할 수 있습니다. 코드를 변경하지 않으면 청록색 배포와 같은 다양한 배포 시나리오를 처리할 수 있습니다.

다음 단계