To send out the TxAasyncStart, we have to intercept the async invocation to send out the event. It's could be a challenge for us to list all the async invocation.
Willem Jiang Twitter: willemjiang Weibo: 姜宁willem On Tue, Jul 30, 2019 at 8:40 AM Willem Jiang <willem.ji...@gmail.com> wrote: > > According to the feedback for PR, I think we need to rethink about the > SagaEnd implementation in the Async invocation scenario. Normally it's > harmless we close the Saga transaction later, but we need to make sure > all the ongoing local transaction are finished. > > In the old way, Alpha can know nothing about the start of Async > Componseable transaction if the TxStartedEvent is not sent, so my > propose that we introduce a new event TxAsyncStart to tell Alpha there > is new Async invocation, so Alpha can keep tracking this Async > invocation event the Componseable transaction is not started yet. In > this way we could block the Async invocation if the Saga transaction > is timeout or close the Saga transaction if all the TxAsyncStart > transaction is finished. > > Any thoughts? > > Willem Jiang > > Twitter: willemjiang > Weibo: 姜宁willem > > On Mon, Jul 29, 2019 at 5:32 PM Willem Jiang <willem.ji...@gmail.com> wrote: > > > > Export the low level API could introduce some error if the user > > doesn't use the API rightly. > > My suggestion is we just > > BTW, I submit a PR[1] to address this issue in a simple way (But we > > still need to tell user what's the right way to configure the > > annotation attribute). > > > > [1]https://github.com/apache/servicecomb-pack/pull/517 > > > > Willem Jiang > > > > Twitter: willemjiang > > Weibo: 姜宁willem > > > > On Thu, Jul 25, 2019 at 8:44 PM Daniel Qian <chanjars...@gmail.com> wrote: > > > > > > Hi Zhang Lei, > > > > > > What I'm trying to say is to provide a way for user to send > > > TxEndedEvent, TxAbortedEvent, TxCompensatedEvent, SagaEndedEvent ... > > > explicitly on Omega side. > > > Because current implementation doesn't support following situation(async): > > > > > > @Compensable(compensationMethod="rollbackFoo") > > > public void foo() { > > > new Thread(() -> /* local tx goes here */).start(); > > > // TxEndedEvent sent when returns, it's too early > > > } > > > > > > public void rollbackFoo() { > > > new Thread(() -> /* compensation goes here*/).start(); > > > // TxCompensatedEvent sent when returns, it's too early > > > } > > > > > > @SagaStart > > > public void bar() { > > > new Thread(() -> /* call other service goes here */).start(); > > > // SagaEndedEvent sent when returns, it's too early > > > } > > > > > > I suggest providing a helper class, called omega or something else, > > > user can use it to send TxEndedEvent, TxAbortedEvent, > > > TxCompensatedEvent, SagaEndedEvent, etc. So the code goes like this: > > > > > > @Compensable(async=true, compensationMethod="rollbackFoo", > > > compensationAsync=true) > > > public void foo() { > > > TransactionContext txContext = omegaContext.getTransactionContext(); > > > new Thread(() -> { > > > try { > > > /* local tx goes here */ > > > omega.txEnded(txContext); > > > } catch(Exception e) { > > > omega.txAborted(txContext); > > > } > > > }).start(); > > > } > > > > > > public void rollbackFoo() { > > > TransactionContext txContext = omegaContext.getTransactionContext(); > > > new Thread(() -> { > > > /*compensation goes here*/ > > > omega.txCompensated() > > > }).start(); > > > } > > > > > > @SagaStart(async=true) > > > public void bar() { > > > TransactionContext txContext = omegaContext.getTransactionContext(); > > > new Thread(() -> { > > > /* call other service goes here */ > > > try { > > > omega.sagaEnded(txContext); > > > } catch (Exception e) { > > > omega.sagaAborted(txContext); > > > } > > > }).start(); > > > } > > > > > > > > > Zhang Lei <zhang_...@boco.com.cn> 于2019年7月25日周四 下午4:46写道: > > > > > > > > > Zhang Lei <zhang_...@boco.com.cn> 于2019年7月25日周四 下午4:46写道: > > > > > > > > Hi, Daniel Qian > > > > > > > > Are you talking about the asynchronous problem with the @SagaStart and > > > > @Compensable methods on the Omega side? I think this is a typical long > > > > transaction scene. > > > > > > > > Alpha based on Actor model has implemented asynchronous processing of > > > > Omega and Alpha, The event sent to Alpha needs to ensure that all child > > > > transactions have been executed before sending SagaEndedEvent or > > > > SagaAbortedEvent. > > > > > > > > Lei Zhang > > > > > > > > > 在 2019年7月20日,下午9:49,Daniel Qian <chanjars...@gmail.com> 写道: > > > > > > > > > > After look into SCB-163, SCB-1385 and SCB-1386 I have some thoughts > > > > > on Saga > > > > > involved in async invocation. > > > > > Current implementation is basically based on sync invocation, there > > > > > are > > > > > some assumption: > > > > > > > > > > 1. When @SagaStart method returns, the Saga finished. > > > > > 2. When @Compensable method returns/throws exception, the Local Tx > > > > > succeeds/failed. > > > > > 3. When compensationMethod returns, the Local Tx is compensated. > > > > > > > > > > Even if considering what SCB-100 provided: > > > > > > > > > > 1. Add @OmegaContextAware annotation enabling > > > > > java.util.concurrent.Executor inject OmegaConext into threads it > > > > > manages/spawns > > > > > 2. Make OmegaContext use InheritableThreadLocal field let child > > > > > thread > > > > > inherit parent thread's Local Tx info > > > > > > > > > > There are still some limitations: > > > > > > > > > > 1. @OmegaContextAware is only viable if you use spring framework > > > > > 2. @OmegaContextAware and OmegaContext's InheritableThreadLocal > > > > > field > > > > > assuming that the calling thread or initator thread has Local Tx > > > > > info. > > > > > > > > > > > > > > > What if user code use producer-consumer pattern in which > > > > > InheritableThreadLocal can't work? > > > > > What if user code use a thread scheduling library which we cannot use > > > > > @OmegaContextAware,RxJava and Reactor, for example? > > > > > I think we could provide some low-level APIs that user code can > > > > > manualy > > > > > starts/ends Saga and Local Tx, something like below: > > > > > > > > > > TxContext context = omega.startSaga(); > > > > > TxContext subTxContext = omega.startTx(TxContext parentTxContext); > > > > > omega.endTx(TxContext); > > > > > omega.abortTx(TxContext); > > > > > omega.abortSaga(TxContext); > > > > > omega.endSaga(TxContext); > > > > > > > > > > TxContext is just a immutable dto like this: > > > > > > > > > > public class TxContext { > > > > > private final String globalTxId; > > > > > private final String localTxId; > > > > > } > > > > > > > > > > Above is a just a rough idea. So any thoughts? > > > > > -- > > > > > Daniel Qian > > > > > > > > > > 博客:https://segmentfault.com/u/chanjarster > > > > > github:https://github.com/chanjarster > > > > > > > > > > > > > -- > > > Daniel Qian > > > > > > 博客:https://segmentfault.com/u/chanjarster > > > github:https://github.com/chanjarster