2017-12-03 4 views
0

I가 내가 다시 시작하고 다시 배우로 실패 메시지를 다시 시도하고 다음과 배우 :Akka.Net PreRestart 실행하지 않을 경우 비동기 처리기에서 예외

public class BuildActor : ReceivePersistentActor 
{ 
    public override string PersistenceId => "asdad3333"; 

    private readonly IActorRef _nextActorRef; 

    public BuildActor(IActorRef nextActorRef) 
    { 
     _nextActorRef = nextActorRef; 

     Command<Workload>(x => Build(x)); 

     RecoverAny(workload => 
     { 
      Console.WriteLine("Recovering"); 
     }); 
    } 

    public void Build(Workload Workload) 
    { 
     var context = Context; 
     var self = Self; 

     Persist(Workload, async x => 
     { 
      //after this line executes 
      //application goes into break mode 
      //does not execute PreStart or Recover 
      var workload = await BuildTask(Workload); 

      _nextActorRef.Tell(workload); 

      context.Stop(self); 
     }); 
    } 

    private Task<Workload> BuildTask(Workload Workload) 
    { 
     //works as expected if method made synchronous 
     return Task.Run(() => 
     { 
      //simulate exception 
      if (Workload.ShowException) 
      { 
       throw new Exception(); 
      } 

      return Workload; 
     }); 
    } 

    protected override void PreRestart(Exception reason, object message) 
    { 
     if (message is Workload workload) 
     { 
      Console.WriteLine("Prestart"); 

      workload.ShowException = false; 

      Self.Tell(message); 
     } 
    } 
} 

내가 Persist의 성공 핸들러 내부 throw되는 예외를 시뮬레이트하려고하지만 예외적으로 응용 프로그램이 중단 모드로 들어가고 PreRestart 후크가 호출되지 않습니다. 그러나 만약 BuildTask 메서드를 Task.Run을 제거하여 동기식으로 만들면 예외가 발생하면 PreRestartRecover<T> 메서드가 모두 호출됩니다.

누군가가이 패턴을 추천 받아야 할 부분과 내가 잘못 될 부분을 지적 할 수 있다면 정말 감사 할 것입니다.

+1

지속성과 관련이 있습니까? 비동기 메서드에서 예외가 발생하면 내 전체 액터 시스템이 종료되고 지속성을 사용하지 않는 것을 상기합니다. 비동기 호출이 모든 예외를 포착하고 대신 몇 가지 오류 메시지가있는 Tell을 수행하도록 코딩이 끝났습니다. ("실패하자"철학으로 멋지게 앉아 있지는 않지만 적절한 해결책이었습니다.) – mwardm

답변

2

아마도, Akka.Persistence는 여기에서 문제를 해결하는 좋은 해결책이 아닙니다.

Akka.Persistence는 액터의 상태 저장을 위해 eventsourcing 원칙을 사용합니다. 이러한 맥락에서 중요한 몇 가지 주요 포인트는 : 당신이 배우에게 보내는 무엇

  • 하는 명령입니다. 그것은 당신이하고 싶은 직업을 묘사합니다. 이 명령을 실행하면 실제 처리가 이루어질 수 있으며 결국 이벤트의 형태로 영구 작업자의 선형 상태 변경 내역으로 이어질 수 있습니다.
  • Persist 방법은 이벤트 저장하는 데에만 사용됩니다 Akka.NET에서
  • - 그들이 뭔가가 일어난 것을, 사실을 설명 : 그, 그들은 거부 할 수 없기 때문에 그들은 (당신이하고있는 일을 실패 할 수 있습니다 Persist 콜백에 있음).
  • 액터가 어느 시점에서든 재시작 할 때 액터는 마지막으로 알려진 시점까지 모든 이벤트 Persist을 재생하여 항상 자신의 상태를 재생성하려고 시도합니다. 이런 이유로 Recover 메서드는 액터의 상태 재생에만 집중해야하며 (동일한 이벤트에 대해 여러 번 호출 될 수 있음) 부작용이 발생하지 않는 것이 중요합니다 (부작용의 예는 전자 메일을 보냅니다). 거기에 던져진 예외는 그 배우 국가가 회복 불가능하게 손상되어 그 배우가 죽을 것이라는 것을 의미합니다.

당신이 배우로 메시지를 다시하려는 경우, 당신은 할 수 :

  1. 은 신뢰할 수있는 메시지 큐 (즉, RabbitMQ 또는 푸른 서비스 버스)를 넣거나 앞에 (카프카 또는 이벤트 허브)를 기록 액터 처리 파이프 라인. 이것은 실제로 많은 경우에 가장 합리적인 시나리오입니다.
  2. at-least-once delivery 의미를 Akka.Persistence에서 사용합니다. 그러나 IMHO는 어떤 이유로 든 첫 번째 해결 방법을 사용할 수없는 경우에만 사용합니다.
  3. 가장 단순하고 신뢰할 수없는 옵션 (메시지가 메모리에만 저장되고 지속되지 않음)은 dead letter queue입니다. 모든 처리되지 않은 메시지가 보내집니다. 메시지를 구독하고 들어오는 데이터를 필터링하여 수신자에게 다시 보낼 메시지를 검색 할 수 있습니다.
관련 문제