servicecomb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Zhang Lei <zhang_...@boco.com.cn>
Subject Re: [DISCUSSION] Async support for Saga
Date Tue, 30 Jul 2019 13:33:19 GMT
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 <willem.jiang@gmail.com> 写道:
> 
> 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.jiang@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.jiang@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 <chanjarster@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_lei@boco.com.cn> 于2019年7月25日周四 下午4:46写道:
>>>> 
>>>> 
>>>> Zhang Lei <zhang_lei@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 <chanjarster@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


Mime
View raw message