문제

몇 가지 작업을 함께 수행하는 가장 좋은 방법은 무엇이며 한 작업이 실패하면 다음 작업이 완료되지 않아야합니까? 데이터베이스 운영인지 여부는 트랜잭션을 사용해야했지만 다음과 같은 다양한 유형의 작업에 대해 이야기하고 있습니다.

모든 작업은 다음과 같습니다.

SendEmail ArchivereportSindatabase Createavile

위의 시나리오에서 모든 작업은 통과해야합니다. 그렇지 않으면 전체 배치 작업이 롤백이어야합니다.

도움이 되었습니까?

해결책

예외는 일반적으로 이런 종류의 일에 좋습니다. Pseudo-Java/JavaScript/C ++ 코드 :

try {
    if (!SendEmail()) {
        throw "Could not send e-mail";
    }

    if (!ArchiveReportsInDatabase()) {
        throw "Could not archive reports in database";
    }

    if (!CreateAFile()) {
        throw "Could not create file";
    }

    ...

} catch (Exception) {
    LogError(Exception);
    ...
}

당신의 방법이 스스로 예외를 던지는 경우에도 더 좋습니다.

try {
    SendEmail();
    ArchiveReportsInDatabase();
    CreateAFile();
    ...

} catch (Exception) {
    LogError(Exception);
    ...
}

이 스타일의 아주 좋은 결과는 작업 체인을 내려 가면서 코드가 점점 더 들여 쓰기되지 않는다는 것입니다. 모든 방법 호출은 동일한 계약 수준으로 유지됩니다. 너무 많이 들여 쓰기로 인해 코드를 읽기가 더 어려워집니다.

또한 오류 처리, 로깅, 롤백 등에 대한 코드의 단일 포인트가 있습니다.

다른 팁

롤백은 힘들다 - Afaik, 실제로는 2 가지 방법이 있습니다. 어느 쪽이든 2 단계 커밋 프로토콜, 또는 보상 거래. 이 패션 중 하나에서 작업을 구성하는 방법을 찾아야합니다.

일반적으로 더 나은 아이디어는 다른 사람들의 노력을 활용하고 이미 2PC 또는 보상이 내장 된 기술을 사용하는 것입니다. 이것이 RDBM이 인기있는 이유 중 하나입니다.

따라서 세부 사항은 작업 의존적이지만 패턴은 매우 쉽습니다.

class Compensator {
   Action Action { get; set; }
   Action Compensate { get; set; }
}

Queue<Compensator> actions = new Queue<Compensator>(new Compensator[] { 
   new Compensator(SendEmail, UndoSendEmail),
   new Compensator(ArchiveReportsInDatabase, UndoArchiveReportsInDatabase),
   new Compensator(CreateAFile, UndoCreateAFile)
});

Queue<Compensator> doneActions = new Queue<Compensator>();
while (var c = actions.Dequeue() != null) {
   try {
      c.Action();
      doneActions.Add(c);
   } catch {
      try {
        doneActions.Each(d => d.Compensate());
      } catch (EXception ex) {
        throw new OhCrapException("Couldn't rollback", doneActions, ex);
      }
      throw;
   }
}

물론 특정 작업의 경우 운이 좋을 수 있습니다.

  • 분명히, RDBMS 작업은 이미 거래에 싸여있을 수 있습니다.
  • Vista 또는 Server 2008에 있다면 거래 NTF CreateFile 시나리오를 다루기 위해.
  • 이메일은 약간 까다 롭습니다 - 나는 그 주변의 2pc 또는 보상자를 모른다 (누군가가 Exchange가 하나가 있다고 지적하면 약간 놀랐습니다). MSMQ 알림을 작성하고 가입자가 가져 와서 결국 이메일을 보내십시오. 그 시점에서, 당신의 거래는 실제로 메시지를 대기열로 보내는 것을 포함하지만 아마도 충분할 것입니다.

이 모든 것은 a에 참여할 수 있습니다 SYSTEM.TRANSACTION 거래, 그래서 당신은 꽤 좋은 모양이어야합니다.

C#에서

return sendemail () && archiveresportsindatabase () && createafile ();

다른 아이디어 :

try {
    task1();
    task2();
    task3();
    ...
    taskN();
}
catch (TaskFailureException e) {
    dealWith(e);
}

몇 가지 제안 :

분산 시나리오에서는 일종의 2 단계 커밋 프로토콜이 필요할 수 있습니다. 본질적으로, 당신은 모든 참가자에게 "x를 준비"하는 메시지를 보냅니다. 그런 다음 각 참가자는 "좋아요, x를 할 수 있다고 보장합니다"또는 "아니요, 할 수 없습니다"라는 응답을 보내야합니다. 모든 참가자가 완료 할 수 있다고 보장하면 메시지를 보내도록 메시지를 보내십시오. "보증"은 필요에 따라 엄격 할 수 있습니다.

또 다른 방법은 각 작업에 대한 일종의 실행 취소 메커니즘을 제공 한 다음 다음과 같은 논리를 갖는 것입니다.

try:
    SendEmail()
    try:
        ArchiveReportsInDatabase()
        try:
             CreateAFile()
        except:
            UndoArchiveReportsInDatabase()
            raise
    except:
        UndoSendEmail()
        raise
except:
    // handle failure

(코드가 그렇게 보이는 것을 원하지 않을 것입니다. 이것은 논리가 어떻게 흐르는지에 대한 예입니다.)

당신의 언어가 그것을 허용한다면, 이것은 매우 깔끔합니다.

  1. 작업을 다양한 코드 블록 또는 기능 포인터에 넣으십시오.
  2. 배열을 반복하십시오.
  3. 블록이 실패를 반환하면 깨집니다.

어떤 프로그래밍 언어/환경을 사용하고 있는지 언급하지 않았습니다. .NET 프레임 워크 인 경우 이 기사. Microsoft의 Robotics Studio의 동시성 및 제어 런타임을 설명합니다. 이는 일련의 (비동기) 이벤트에 모든 종류의 규칙을 적용 할 수 있습니다. 예를 들어, 여러 규칙이 완료되기를 기다릴 수 있습니다. 하나의 이벤트가 실패하면 취소하십시오. 등. 여러 스레드에서도 실행할 수 있으므로 매우 강력한 작업을 수행 할 수 있습니다.

당신은 당신의 환경을 지정하지 않습니다. Unix Shell 스크립팅에서 && 운영자는이 작업을 수행합니다.

SendEmail () {
  # ...
}
ArchiveReportsInDatabase () {
  # ...
}
CreateAFile () {
  # ...
}

SendEmail && ArchiveReportsInDatabase && CreateAFile

사용하는 언어를 사용하는 경우 정렬 회로 평가 (Java 및 C# do), 간단히 할 수 있습니다.

return SendEmail() && ArchiveResportsInDatabase() && CreateAFile();

모든 기능이 True를 반환하면 True가 반환되고 첫 번째 기능이 False를 반환하자마자 중지됩니다.

실제로 올바르게하려면 비동기 메시징 패턴을 사용해야합니다. 방금 사용했던 프로젝트를 마쳤습니다. nservicebus 및 MSMQ.

기본적으로 각 단계는 큐에 메시지를 보내어 발생합니다. nservicebus가 큐에서 대기하는 메시지를 찾으면 해당 메시지 유형에 해당하는 핸들 메소드를 호출합니다. 이런 식으로 각 개별 단계는 독립적으로 실패하고 재 시도 할 수 있습니다. 한 단계가 실패하면 메시지가 오류 큐에서 끝나기 때문에 나중에 쉽게 다시 시도 할 수 있습니다.

제안되는 이러한 순수 코드 솔루션은 단계가 실패하면 미래의 한 단계 만 재 시도 할 수 없으며 어떤 경우에는 불가능한 롤백 코드를 구현해야하기 때문에 강력하지 않습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top