Hi, Willem

Do you mean by sending a TxAsyncStartEvent to Alpha before executing the 
asynchronous method?

Conversation:

Omega: Hi, Alpha an asynchronous method is about to start, please wait until 
you received sub-transaction events
Alpha:    Ok, I will wait until I receive a TxStartedEvent and a TxEndedEvent 
or a TxAbortedEvent before ending the transaction.

Lei Zhang


> 在 2019年7月30日,上午8:49,Willem Jiang <[email protected]> 写道:
> 
> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 于2019年7月25日周四 下午4:46写道:
>>>> 
>>>> 
>>>> Zhang Lei <[email protected]> 于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 <[email protected]> 写道:
>>>>>> 
>>>>>> 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

Reply via email to