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