완료하는 분산 트랜잭션 (EnterpriseServicesInteropOption.Full) 및 영구 가입자를 사용하는 경우, TransactionScope.Dispose 방법은 모든 커밋을 기다리지 않습니다 것 같다 편집 할 수 있지만 단지 메소드 호출과 TransactionCompleted 이벤트로 급부상 배경 스레드.TransactionScope가 모든 커밋을 호출했는지 확인하는 방법은 무엇입니까?
이 명확하게 내용의 문서에 부합되지 않습니다 트랜잭션이 커밋 또는 중단 될 때까지
이 방법은 동기 및 블록.
모든 커밋이 처리 된 시점을 판단하는 방법이없는 것 같습니다. 콘솔 응용 프로그램에서는 주 스레드가 처리 후에 종료 될 수 있고 이로 인해 모든 백그라운드 스레드가 효과적으로 제거되기 때문에 문제가 발생합니다. 분산 된 트랜잭션의 원격 참가자는이 사실을 알리지 않을 것이므로 잠긴 상태, 제한 시간 및 기타 못생긴 결과가 발생합니다 ...
또 다른 문제점은 새로운 TransactionScope가 생성 될 때 참가자가 여전히 연결될 수 있다는 것입니다 새로운 거래 내에서 등록 될 것으로 예상되는 경우 이전 거래로
아래 (단순화 된) 코드는이 문제를 보여줍니다.
내 질문 : 아무도 새로운 루프를 시작하는 것이 안전한지 여부를 결정하는 방법을 알고 있습니까? 나는 worker 코드에 접근 할 수 없기 때문에 아무 것도 변경할 수 없다. Thread.Sleep (1000)을 추가하면 문제는 해결되지만 그 결과는 문제를 해결한다 ...
EDITED
internal class TransactionScopeTest
{
[STAThread]
public static void Main()
{
var transactionOptions = new TransactionOptions { Timeout = TransactionManager.DefaultTimeout };
var worker = new Worker();
var transactionCompletedEvent = new AutoResetEvent(true); // true to start a first loop
while (true)
{
transactionCompletedEvent.WaitOne(); // wait for previous transaction to finish
Log("Before TransactionScope");
using (var tx = new TransactionScope(TransactionScopeOption.Required, transactionOptions, EnterpriseServicesInteropOption.Full))
{
Log("Inside TransactionScope");
Transaction.Current.TransactionCompleted += delegate
{
transactionCompletedEvent.Set(); // allow a next loop to start
Log("TransactionCompleted event");
};
worker.DoWork();
Log("Before commit");
tx.Complete();
Log("Before dispose");
}
Log("After dispose");
}
}
private static void Log(string message)
{
Console.WriteLine("{0} ({1})", message, Thread.CurrentThread.ManagedThreadId);
}
public class Worker : IEnlistmentNotification
{
private Transaction _transaction;
private readonly Guid _id = Guid.NewGuid();
public void Prepare(PreparingEnlistment preparingEnlistment)
{
Log("Preparing");
preparingEnlistment.Prepared();
}
public void Commit(Enlistment enlistment)
{
Log("Committing");
_transaction = null;
enlistment.Done();
}
public void Rollback(Enlistment enlistment)
{
Log("Rolling back");
_transaction = null;
enlistment.Done();
}
public void InDoubt(Enlistment enlistment)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "Doubting");
_transaction = null;
enlistment.Done();
}
public void DoWork()
{
Enlist();
Log("Doing my thing...");
}
private void Enlist()
{
if (_transaction == null) //Not yet enlisted
{
Log("Enlisting in transaction");
_transaction = Transaction.Current;
_transaction.EnlistDurable(_id,this, EnlistmentOptions.EnlistDuringPrepareRequired);
return;
}
if (_transaction == Transaction.Current) //Already enlisted in current transaction
{
return;
}
throw new InvalidOperationException("Already enlisted in other transaction");
}
}
}
출력 :
Before commit (1)
Before dispose (1)
Preparing (6)
After dispose (1)
Committing (6)
TransactionCompleted event (7)
Before TransactionScope (1)
Inside TransactionScope (1)
Enlisting in transaction (1)
Doing my thing... (1)
Before commit (1)
Before dispose (1)
Preparing (7)
After dispose (1)
Before TransactionScope (1)
TransactionCompleted event (7)
Inside TransactionScope (1)
Committing (6)
Unhandled Exception: System.InvalidOperationException: Already enlisted in other transaction
어떻게 해결 되었습니까? 나는 IBM MQ를 사용하여 동일한 질문을한다. – cudima
답변으로 구현 한 코드를 추가했습니다. 결코 결정적인 해결책은 아니지만 찾을 수있는 최선입니다. –