검색

9.4. 예

download PDF

예를 들어, 새 주문을 배치하고, 시스템에 두 개의 고유한 서비스(명령을 관리하는 방법과 신용을 관리하는 서비스)가 있습니다. 논리적으로는 충분한 크레딧이 있는 경우 주문을 할 수 있습니다. saga EIP를 사용하면 direct:buy 경로를 두 가지 고유한 작업으로 구성된 saga로 모델링할 수 있습니다. 하나는 순서를 만들고 신용을 취할 것입니다. 두 작업을 모두 실행하거나 신용없이 주문한 주문 중 어느 것도 일관되지 않은 결과 (주문없이 지불)로 간주 될 수 없습니다.

from("direct:buy")
  .saga()
    .to("direct:newOrder")
    .to("direct:reserveCredit");

나머지 예제에는 구매 동작이 변경되지 않습니다. 새 주문 및 예약 credit 작업을 모델링하는 데 사용되는 다양한 옵션은 다음과 같습니다.

from("direct:newOrder")
  .saga()
  .propagation(SagaPropagation.MANDATORY)
  .compensation("direct:cancelOrder")
    .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
    .bean(orderManagerService, "newOrder")
    .log("Order ${body} created");

여기서 전파 모드는 MANDATORY 로 설정되어 있습니다. 즉, 이 경로의 모든 교환 흐름이 이미 saga의 일부여야 한다는 것을 의미합니다(사이크가 직접:buy 경로에서 생성되기 때문에 이 예제의 경우). direct:newOrder 경로는 saga가 취소되는 경우 순서를 취소할 책임이 있는 direct:cancelOrder 라는 보완 조치를 선언합니다.

각 교환에는 항상 여기에서 주문 ID로 사용되는 Exchange.SAGA_LONG_RUNNING_ACTION 헤더가 포함되어 있습니다. 이는 해당 조정 작업에서 삭제할 순서를 식별하지만 필수 사항은 아닙니다(옵션을 대체 솔루션으로 사용할 수 있음). 직접:newOrder 의 조정 작업은 직접:cancelOrder 이며 다음과 같습니다.

from("direct:cancelOrder")
  .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
  .bean(orderManagerService, "cancelOrder")
  .log("Order ${body} cancelled");

사가 EIP 구현에 의해 주문이 취소되어야 할 때 자동으로 호출됩니다. 오류와 함께 종료되지 않습니다. direct:cancelOrder 경로에서 오류가 발생한 경우 EIP 구현은 특정 제한까지 조정 작업을 실행하기 위해 주기적으로 재시도해야 합니다. 즉, 조정 작업은 멱등이어야 하므로 여러 번 트리거될 수 있으며 어떤 경우에도 실패하지 않아야 합니다. 모든 재시도 후 보수를 수행할 수 없는 경우 saga 구현을 통해 수동 개입 프로세스를 트리거해야 합니다.

참고

직접:newOrder 경로의 실행 지연으로 인해 saga는 다른 당사자가 그 동안 다른 당사자에 의해 취소됩니다 (병렬 경로의 오류 또는 사파르 수준의 시간 초과로 인해 발생할 수 있습니다). 따라서 강제 조치 direct:cancelOrder 가 호출되면 취소된 주문 레코드를 찾을 수 없습니다. 완전한 글로벌 일관성을 보장하기 위해서는 모든 주요 조치와 해당 조정 작업은 예를 들어 주 동작이 동일해야합니다.

변경 동작을 사용할 수 없는 또 다른 접근 방식은 기본 작업으로 생성된 데이터가 발견되거나 최대 재시도 횟수가 소진될 때까지 지속적으로 보완적인 조치에 실패하는 것입니다. 이 접근 방식은 많은 상황에서 작동할 수 있지만 추론 적입니다.

신용 서비스는 주문 서비스와 거의 동일한 방식으로 구현됩니다.

from("direct:reserveCredit")
  .saga()
  .propagation(SagaPropagation.MANDATORY)
  .compensation("direct:refundCredit")
    .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
    .bean(creditService, "reserveCredit")
    .log("Credit ${header.amount} reserved in action ${body}");

보수 조치에 대한 전화:

from("direct:refundCredit")
  .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
  .bean(creditService, "refundCredit")
  .log("Credit for action ${body} refunded");

여기에서 신용 예약에 대한 보완 조치는 취소입니다. 이 예제는 원격 엔드포인트와 관련이 없으므로 saga EIP의 두 구현에서 실행할 수 있습니다.

9.4.1. 완료 이벤트 처리

saga가 완료되면 일부 유형의 처리가 필요합니다. 보수 끝점은 문제가 발생하여 saga가 취소될 때 호출됩니다. saga가 성공적으로 완료되면 완료 끝점 을 호출하여 추가 처리를 수행할 수 있습니다. 예를 들어 위의 주문 서비스에서 실제로 주문 준비를 시작하기 위해 주문이 완료되는 시점과 예약된 신용을 알아야 할 수 있습니다. 결제가 완료되지 않은 경우 주문 준비를 시작하지 않는 것이 좋습니다(읽기 권한을 보장하기 전에 예약된 메모리에 대한 액세스 권한을 부여하는 최신 CPU와 달리). 이 작업은 수정된 direct:newOrder 끝점으로 쉽게 수행할 수 있습니다.

  1. completeion 끝점을 호출합니다.
from("direct:newOrder")
  .saga()
  .propagation(SagaPropagation.MANDATORY)
  .compensation("direct:cancelOrder")
  .completion("direct:completeOrder")
    .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
    .bean(orderManagerService, "newOrder")
    .log("Order ${body} created");
  1. direct:cancelOrder 는 이전 예와 동일합니다. 다음과 같이 성공적인 완료를 호출합니다.
from("direct:completeOrder")
  .transform().header(Exchange.SAGA_LONG_RUNNING_ACTION)
  .bean(orderManagerService, "findExternalId")
  .to("jms:prepareOrder")
  .log("Order ${body} sent for preparation");

saga가 완료되면 준비를 위해 명령이 JMS 큐로 전송됩니다. 조정 동작과 마찬가지로 완료 작업은 사가 코디네이터(특히 네트워크 오류와 같은 오류의 경우)에 의해 여러 번 호출될 수 있습니다. 이 예에서 prepareOrder JMS 큐를 수신하는 서비스는 가능한 중복을 보유할 준비가 되었습니다(복제 처리 방법에 대한 예제는 Idempotent Consumer EIP 참조).

9.4.2. 사용자 정의 식별자 및 옵션 사용

sa 옵션을 사용하여 사용자 정의 식별자를 등록할 수 있습니다. 예를 들어, 신용 서비스는 다음과 같이 리팩터링됩니다.

  1. 사용자 지정 ID를 생성하고 다음과 같이 본문에 설정합니다.
from("direct:reserveCredit")
  .bean(idService, "generateCustomId")
  .to("direct:creditReservation")
  1. 위임 작업을 수행하고 조정 작업에 필요한 대로 현재 본문을 표시합니다.
from("direct:creditReservation")
  .saga()
  .propagation(SagaPropagation.SUPPORTS)
  .option("CreditId", body())
  .compensation("direct:creditRefund")
    .bean(creditService, "reserveCredit")
    .log("Credit ${header.amount} reserved. Custom Id used is ${body}");
  1. saga가 취소된 경우에만 헤더에서 creditId 옵션을 검색합니다.
from("direct:creditRefund")
  .transform(header("CreditId")) // retrieve the CreditId option from headers
  .bean(creditService, "refundCredit")
  .log("Credit for Custom Id ${body} refunded");

direct:creditReservation 엔드포인트는 사도 외부에서 호출할 수 있으며, 전파 모드를 SUPPORTS 로 설정하면 됩니다. 이렇게 하면 사가 경로에 여러 옵션을 선언할 수 있습니다.

9.4.3. 시간 초과 설정

saga EIPs에서 시간 초과를 설정하면 시스템 오류 발생 시 saga가 영구적으로 유지되지 않습니다. saga EIP 구현에는 명시적으로 지정하지 않는 모든saga EIP에 설정된 기본 시간 초과가 있습니다. 시간 제한이 만료되면, 사가 EIP는 이전에 다른 결정을하지 않는 한 사가 (모든 참가자를 보완함)를 취소하기 로 결정합니다.

saga 참가자에 시간 초과는 다음과 같이 설정할 수 있습니다.

from("direct:newOrder")
  .saga()
  .timeout(1, TimeUnit.MINUTES) // newOrder requires that the saga is completed within 1 minute
  .propagation(SagaPropagation.MANDATORY)
  .compensation("direct:cancelOrder")
  .completion("direct:completeOrder")
    // ...
    .log("Order ${body} created");

모든 참가자(예: 신용 서비스, 주문 서비스)는 자체 시간 초과를 설정할 수 있습니다. 이러한 시간 초과의 최소 값은 함께 구성될 때 saga의 시간 초과 값으로 사용됩니다. 시간 초과는 다음과 같이 사가 수준에서 지정할 수도 있습니다.

from("direct:buy")
  .saga()
  .timeout(5, TimeUnit.MINUTES) // timeout at saga level
    .to("direct:newOrder")
    .to("direct:reserveCredit");

9.4.4. 전파 선택

위의 예제에서는 다른 항목이 지정되지 않은 경우 사용되는 기본 전파 모드인 MANDATORY , SUPPORTSREQUIRED 전파 모드를 사용합니다. 이러한 전파 모드는 1:1 트랜잭션 컨텍스트에서 사용되는 동등한 모드를 매핑합니다.

전파설명

REQUIRED

기존sa에 가입하거나 존재하지 않는 경우 새 사가를 만듭니다.

REQUIRES_NEW

항상 새 사가를 만듭니다. 이전 사가를 일시 중지한 후 새 서비스가 종료되면 다시 시작합니다.

필수

사도는 이미 존재하고 있어야 합니다. 기존의 saga가 결합됩니다.

SUPPORTS

사가가 이미 존재하는 경우, 여기에 가입하십시오.

NOT_SUPPORTED

saga가 이미 존재하는 경우 현재 블록이 완료되면 일시 중지되고 재개됩니다.

NEVER

현재 블록은 saga 내에서 호출해서는 안 됩니다.

9.4.5. 수동 완료(Advanced) 사용

사가가 모두 동기적으로 실행될 수는 없지만, 예를 들어 비동기식 통신 채널을 사용하는 외부 서비스와의 통신이 필요한 경우,acga는 해당 채널을 생성하는 교환이 완료될 때 완료 모드를 AUTO (기본값)로 설정할 수 없기 때문입니다. 이는 종종 장기 실행 시간 (시간, 일)이 있는 사가 EIP의 경우입니다. 이러한 경우 MANUAL 완료 모드를 사용해야 합니다.

from("direct:mysaga")
  .saga()
  .completionMode(SagaCompletionMode.MANUAL)
  .completion("direct:finalize")
  .timeout(2, TimeUnit.HOURS)
    .to("seda:newOrder")
    .to("seda:reserveCredit");

seda:newOrder 및 seda:reserveCredit에 대한 비동기 처리를 추가합니다. 비동기 콜백을 seda:operationCompleted로 보냅니다.

from("seda:operationCompleted") // an asynchronous callback
  .saga()
  .propagation(SagaPropagation.MANDATORY)
    .bean(controlService, "actionExecuted")
    .choice()
      .when(body().isEqualTo("ok"))
        .to("saga:complete") // complete the current saga manually (saga component)
    .end()

direct:finalize 엔드포인트를 추가하여 최종 작업을 실행할 수 있습니다.

완료 모드를 MANUAL 로 설정하면 경로 direct:mysaga 에서 교환이 처리될 때 saga가 완료되지 않지만 더 오래 지속됩니다(최대 기간은 2시간으로 설정됨). 두 비동기 작업이 모두 완료되면sa가 완료됩니다. Camel saga Component의 saga:complete 엔드포인트를 사용하여 완료되는 호출이 수행됩니다. saga:compensate)를 수동으로 보완하기 위한 유사한 엔드포인트가 있습니다.

Red Hat logoGithubRedditYoutubeTwitter

자세한 정보

평가판, 구매 및 판매

커뮤니티

Red Hat 문서 정보

Red Hat을 사용하는 고객은 신뢰할 수 있는 콘텐츠가 포함된 제품과 서비스를 통해 혁신하고 목표를 달성할 수 있습니다.

보다 포괄적 수용을 위한 오픈 소스 용어 교체

Red Hat은 코드, 문서, 웹 속성에서 문제가 있는 언어를 교체하기 위해 최선을 다하고 있습니다. 자세한 내용은 다음을 참조하세요.Red Hat 블로그.

Red Hat 소개

Red Hat은 기업이 핵심 데이터 센터에서 네트워크 에지에 이르기까지 플랫폼과 환경 전반에서 더 쉽게 작업할 수 있도록 강화된 솔루션을 제공합니다.

© 2024 Red Hat, Inc.