1 2 3 Previous Next 32 Replies Latest reply on Dec 3, 2018 9:58 AM by tomjenkinson

    Registering transaction synchronization during time of beforeCompletion

    ochaloup

      Hello,

       

      I've been investigating the issue based on the query on the stackoverflow hibernate - Defer TransactionalObserverNotifier fails with ARJUNA016082: Synchronizations are not allowed (issues filled for WELD/CDI - WELD-2444, CDI-724). I started looking at it from Narayana perspective.

      The issue WELD-2444 is nicely described and I created the reproducer for the WFLY testsuite. martinkouba mentions that the behavior is correct based on the CDI specification. I wonder if it's an issue of the Narayana code. Or in case the transaction integration in WFLY.

       

      What happens

      The Hibernate synchronization (Synchronization (Java(TM) EE 7 Specification APIs) ) runs code of the method @PostPersist. Because this is the JPA synchronization it has to be specifically ordered against the JCA synchronization (based on the comment in the wildfly/TransactionSynchronizationRegistryWrapper.java at master · wildfly/wildfly · GitHub  that's why there is the wildfly/JCAOrderedLastSynchronizationList.java at master · wildfly/wildfly · GitHub  created). The code of the @PostPersist method drives (via CDI event) a new synchronization to be added. This flows up to the TwoPhaseCoordinator class to addSynchronization method (narayana/TwoPhaseCoordinator.java at master · jbosstm/narayana · GitHub ). There is linked issue [JBTM-608] Allow synchronization registration as long as beforeCompletion phase not finished - JBoss Issue Tracker  which says that registering the synchronization on beforeCompletion should be possible. But here it isn't as the synchronization that would be added is *non* interposed (aka. it's normal synchronization). But the last executed synchronization is the JCAOrderedLastSynchronizationList which is interposed thus running as the last (after all normal *non* interposed ones). Because of that the code decline to add such synchronization as the new one is smaller when compared to the _currentRecord (narayana/SynchronizationImple.java at master · jbosstm/narayana · GitHub ). The exception is thrown and it causes what is described at the stackoverflow/in the issue.

      (The newly adding synchronization would be run only afterCompletion).

       

      Should not be permitted to add the new synchronization in way the logic in TwoPhaseCoordinator would care only about ordering but not about the fact the synchronization is interposed? I mean when interposed synchronization is already running then it won't happen that when there is added new synchronization to the 'sync' treemap that this new synchronization would be launched after that, right. I mean when interposed synchronizations are already running Narayana won't touch to the normal one again. (it seems so from my experiments too).

       

      Do you think synchronization could be added just based on the ordering without considering the interposed flag?

       

      Thank you for ideas

      Ondra

       

      Stacktrace at time the new (eventually failing synchronization) should be registered

      Thread [default task-1] (Suspended) 
       owns: Object  (id=562) 
       AtomicAction(TwoPhaseCoordinator).addSynchronization(SynchronizationRecord) line: 168 
       TransactionImple.registerSynchronizationImple(SynchronizationImple) line: 388 
       TransactionImple.registerSynchronization(Synchronization) line: 377 
       LocalTransaction.registerSynchronization(Synchronization) line: 179 
       WeldTransactionServices.registerSynchronization(Synchronization) line: 97 
       TransactionalObserverNotifier.notifyTransactionObservers(List<ObserverMethod<? super T>>, T, EventMetadata, ObserverExceptionHandler) line: 86 
       TransactionalObserverNotifier(ObserverNotifier).notify(ResolvedObservers<T>, T, EventMetadata) line: 274 
       EventImpl<T>.fire(T) line: 96 
       TestPersistEntityListener.onEntityPostPerist(Object) line: 42 
       NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] 
       NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62 
       DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 
       Method.invoke(Object, Object...) line: 498 
       ListenerCallback.performCallback(Object) line: 35 
       CallbackRegistryImpl.callback(Callback[], Object) line: 97 
       CallbackRegistryImpl.postCreate(Object) line: 66 
       PostInsertEventListenerStandardImpl.onPostInsert(PostInsertEvent) line: 31 
       EntityInsertAction.postInsert() line: 168 
       EntityInsertAction.execute() line: 135 
       ActionQueue.executeActions(ExecutableList<E>) line: 604 
       ActionQueue.executeActions() line: 478 
       DefaultFlushEventListener(AbstractFlushingEventListener).performExecutions(EventSource) line: 356 
       DefaultFlushEventListener.onFlush(FlushEvent) line: 39 
       SessionImpl.doFlush() line: 1454 
       SessionImpl.managedFlush() line: 511 
       SessionImpl.flushBeforeTransactionCompletion() line: 3283 
       SessionImpl.beforeTransactionCompletion() line: 2479 
       JdbcCoordinatorImpl.beforeTransactionCompletion() line: 473 
       JtaTransactionCoordinatorImpl.beforeCompletion() line: 352 
       SynchronizationCallbackCoordinatorTrackingImpl(SynchronizationCallbackCoordinatorNonTrackingImpl).beforeCompletion() line: 47 
       RegisteredSynchronization.beforeCompletion() line: 37 
       JCAOrderedLastSynchronizationList.beforeCompletion() line: 113 
       844757553.accept(Object) line: not available 
       22702947.accept(Object, Object) line: not available 
       LocalTransaction(AbstractTransaction).performConsumer(ExceptionBiConsumer<T,U,E>, T, U) line: 236 
       LocalTransaction(AbstractTransaction).performConsumer(ExceptionConsumer<T,E>, T) line: 247 
       AbstractTransaction$AssociatingSynchronization.beforeCompletion() line: 292 
       SynchronizationImple.beforeCompletion() line: 76 
       AtomicAction(TwoPhaseCoordinator).beforeCompletion() line: 360 
       AtomicAction(TwoPhaseCoordinator).end(boolean) line: 91 
       AtomicAction(AtomicAction).commit(boolean) line: 162 
       TransactionImple.commitAndDisassociate() line: 1288 
       TransactionManagerImple(BaseTransaction).commit() line: 126 
       TransactionManagerDelegate(BaseTransactionManagerDelegate).commit() line: 89 
       LocalTransaction.commitAndDissociate() line: 77 
       ContextTransactionManager.commit() line: 71 
       TransactionalInterceptorRequired(TransactionalInterceptorBase).endTransaction(TransactionManager, Transaction) line: 232 
       TransactionalInterceptorRequired(TransactionalInterceptorBase).invokeInOurTx(InvocationContext, TransactionManager) line: 178 
       TransactionalInterceptorRequired.doIntercept(TransactionManager, Transaction, InvocationContext) line: 53 
       TransactionalInterceptorRequired(TransactionalInterceptorBase).intercept(InvocationContext) line: 88 
       TransactionalInterceptorRequired.intercept(InvocationContext) line: 47 
       NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] 
       NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62 
       DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 
       Method.invoke(Object, Object...) line: 498 
       SimpleInterceptorInvocation$SimpleMethodInvocation.invoke(InvocationContext) line: 73 
       InterceptorMethodHandler.executeAroundInvoke(Object, Method, Method, Object[], InterceptorMethodHandler$CachedInterceptionChain, InterceptionDecorationContext$Stack) line: 84 
       InterceptorMethodHandler.executeInterception(Object, Method, Method, Object[], InterceptionType, InterceptionDecorationContext$Stack) line: 72 
       InterceptorMethodHandler.invoke(InterceptionDecorationContext$Stack, Object, Method, Method, Object[]) line: 56 
       CombinedInterceptorAndDecoratorStackMethodHandler.invoke(InterceptionDecorationContext$Stack, Object, Method, Method, Object[], boolean, boolean) line: 79 
       CombinedInterceptorAndDecoratorStackMethodHandler.invoke(InterceptionDecorationContext$Stack, Object, Method, Method, Object[]) line: 68 
       TestEntityManipulatorBean$Proxy$_$$_WeldSubclass.createTestEntity(String) line: not available 
       TransactionalObserverJPAListenerTestCase.commitObserved() line: 80 
       NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] 
       NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62 
       DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 
       Method.invoke(Object, Object...) line: 498 
       FrameworkMethod$1.runReflectiveCall() line: 50 
       FrameworkMethod$1(ReflectiveCallable).run() line: 12 
       FrameworkMethod.invokeExplosively(Object, Object...) line: 47 
       Arquillian$8$1.invoke(Object...) line: 379 
       LocalTestExecuter.execute(LocalExecutionEvent) line: 60 
       NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] 
       NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62 
       DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 
       Method.invoke(Object, Object...) line: 498 
       ObserverImpl.invoke(Manager, Object) line: 96 
       EventContextImpl<T>.invokeObservers() line: 103 
       EventContextImpl<T>.proceed() line: 85 
       ManagerImpl.fire(T, NonManagedObserver<T>) line: 143 
       ManagerImpl.fire(Object) line: 114 
       EventImpl<T>.fire(T) line: 67 
       ContainerTestExecuter.execute(Test) line: 38 
       NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] 
       NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62 
       DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 
       Method.invoke(Object, Object...) line: 498 
       ObserverImpl.invoke(Manager, Object) line: 96 
       EventContextImpl<T>.invokeObservers() line: 103 
       EventContextImpl<T>.proceed() line: 85 
       TestContextHandler.createTestContext(EventContext<TestEvent>) line: 130 
       NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] 
       NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62 
       DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 
       Method.invoke(Object, Object...) line: 498 
       ObserverImpl.invoke(Manager, Object) line: 96 
       EventContextImpl<T>.proceed() line: 92 
       TestContextHandler.createClassContext(EventContext<ClassEvent>) line: 92 
       NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] 
       NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62 
       DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 
       Method.invoke(Object, Object...) line: 498 
       ObserverImpl.invoke(Manager, Object) line: 96 
       EventContextImpl<T>.proceed() line: 92 
       TestContextHandler.createSuiteContext(EventContext<SuiteEvent>) line: 73 
       NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] 
       NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62 
       DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 
       Method.invoke(Object, Object...) line: 498 
       ObserverImpl.invoke(Manager, Object) line: 96 
       EventContextImpl<T>.proceed() line: 92 
       ManagerImpl.fire(T, NonManagedObserver<T>) line: 143 
       EventTestRunnerAdaptor.test(TestMethodExecutor) line: 136 
       Arquillian$8.evaluate() line: 372 
       Arquillian$4.evaluate() line: 246 
       Arquillian.multiExecute(Statement...) line: 431 
       Arquillian.access$200(Arquillian, Statement[]) line: 55 
       Arquillian$5.evaluate() line: 260 
       Arquillian$7$1.invoke() line: 324 
       BeforeLifecycleEventExecuter.on(BeforeTestLifecycleEvent) line: 35 
       NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] 
       NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62 
       DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 
       Method.invoke(Object, Object...) line: 498 
       ObserverImpl.invoke(Manager, Object) line: 96 
       EventContextImpl<T>.invokeObservers() line: 103 
       EventContextImpl<T>.proceed() line: 85 
       TestContextHandler.createTestContext(EventContext<TestEvent>) line: 130 
       NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] 
       NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62 
       DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 
       Method.invoke(Object, Object...) line: 498 
       ObserverImpl.invoke(Manager, Object) line: 96
       EventContextImpl<T>.proceed() line: 92 
       TestContextHandler.createClassContext(EventContext<ClassEvent>) line: 92 
       NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] 
      
      
        • 1. Re: Registering transaction synchronization during time of beforeCompletion
          tomjenkinson

          ochaloup  wrote:

           

           

          Should not be permitted to add the new synchronization in way the logic in TwoPhaseCoordinator would care only about ordering but not about the fact the synchronization is interposed? I mean when interposed synchronization is already running then it won't happen that when there is added new synchronization to the 'sync' treemap that this new synchronization would be launched after that, right. I mean when interposed synchronizations are already running Narayana won't touch to the normal one again. (it seems so from my experiments too).

           

          Do you think synchronization could be added just based on the ordering without considering the interposed flag?

           

          I lost the reasoning a little around here, the items before and after I understand.

           

          We can't allow a session synchronization (Transaction::registerSynchronization) to be registered after the interposed synchronizations are already running as that would contradict elements of the JTA specification related to TransactionSynchronizationRegistry::registerInterposedSynchronization

           

          I am wondering if weld might be able to register an interposed synchronization instead of a session synchronization?

           

          I am also wondering why @PostPersist can be called which the transaction is committing? Perhaps the interceptors should be running those callbacks before .commit()?

           

          /cc smarlow

          • 2. Re: Registering transaction synchronization during time of beforeCompletion
            smarlow

            From my quick read of the issues, we are discussing Hibernate, which is a system level component that registers interposed synchronizations (as recommended by Java EE spec).  Which means that the Hibernate before completion call back is called after session synchronization callbacks are completed, so registering a session synchronization when we are still in the "interposed before completion" stage, seems to be a problem, as we know that the session synchronization before completion will not be called.

             

            We know that its too late to register a session sync, for the session sync before completion callback to be called but we don't really know if that is an error condition, as the application could really just want the session sync after completion to be called.  This does seem like a hole though.

             

            Could it make sense for any session syncs that are registered during the "interposed before completion" stage, to be called immediately after completing the calls to the "interposed before completion"?  I think that this would be wrong from an ordering point of view but maybe it could help in this case.

             

            Regarding @PostPersist, the application could instead manually flush the database changes, before the transaction is ended, which likely would work around this.  @PostPersist callback description from jpa spec "3.5.3 Semantics of the Life Cycle Callback Methods for Entities":

            ...

            The PostPersist and PostRemove callback methods are invoked for an entity after the entity has

            been made persistent or removed. These callbacks will also be invoked on all entities to which these

            operations are cascaded. The PostPersist and PostRemove methods will be invoked after the

            database insert and delete operations respectively. These database operations may occur directly after

            the persist, merge, or remove operations have been invoked or they may occur directly after a flush

            operation has occurred (which may be at the end of the transaction). Generated primary key values are

            available in the PostPersist method.

            ...

             

            Scott

            • 3. Re: Registering transaction synchronization during time of beforeCompletion
              ochaloup

              Thanks tomjenkinson and smarlow.

               

              I will add some more points based on my further investigation.

               

              tomjenkinson : sure, I'm sorry my reasoning was wrong. I wrongly followed the code of the TwoPhaseCoordinator. I I understand now that adding synchronization can't be allowed at time of interposed synchronization is running. At least in way how the code works currently. That's where I would argue that it could be(?). It's what I think Scott names "the hole" and what's happening in this case.

               

              First I think the WELD can't and should not add interposed synchronization. What the WELD tries to add as the synchronization class is a user defined synchronization. It should not be add as interposed as it goes apposed to the facts that interposed synchronization is expected to be used for app container synchronizations and up to that it will be invoked after JCA and JPA, already configured, interposed synchronizations. Which can't happen.

               

              The @PostPesist is called before transaction is committed. It's called at Synchronization.beforeCompletion callback. At that time new synchronization can be added (JBTM-608) but not at time the interposed synchronization is already running.

               

              smarlow yes, I see. The workaround is already described in the issue (WELD-2444). If you agree it's workaround then we can consider the current behavior as an issue. And it depends if it should be solved by CDI change (as proposed at CDI-724). Or if it fix in Narayana could be considered.

               

              My thinking about this issue is now in what's "the hole"? Why I can't add any synchronization during Synchronization.beforeCompletion when I expect this newly added synchronization will take the effect only(!) at time Synchronization.afterCompletion is called?

              tomjenkinson something like this? Comparing jbosstm:master...ochaloup:WELD-2444-jca-ordering-synchronization · jbosstm/narayana · GitHub

              • 4. Re: Registering transaction synchronization during time of beforeCompletion
                tomjenkinson

                The reason you can't register session syncs (even ones that implement afterCompletion only) is just because of the JTA specification compliance we need. Perhaps we could update the specification to discuss that wider in the ee4j community: Mailing List Archives - jta-dev | The Eclipse Foundation  But you mention that Weld is adding is a user defined synchronization - if that is the case how can you be certain it would only define beforeCompletion?

                 

                PS we should definitely not consider fudging the order (session, interposed, session) because the sessions might flush things again and then the interposed not deal with the new flushes and so on.

                 

                PPS the reporter on the CDI issue mentions "I think it might be worthwhile to consider to use an interposed (run last) synchronisation rather than plain transaction synchronisations"

                • 5. Re: Registering transaction synchronization during time of beforeCompletion
                  ochaloup

                  tomjenkinson I'm seeking through the specification but I don't understand what part of the specification you mean. For my better understanding what part do you refer to, please?

                   

                  That's a good point. I'm not sure if they define only beforeCompletion but I know that user decided to register the synchronization at point when only(!) the afterCompletion could be executed. The user defines the synchronization at the place where the beforeCompletion can't be counted with. And if he expects so it's resonable to argue with him that his expectation is senseless

                   

                  ad PS: agree

                  ad PSS: I do not agree with the reporter that this is the correct solution. I agree with him in the point that change of the CDI specification would solve this problem. But I'm unsure if the spec change is what could be called the good solution. I mean in way if this is the place where the specification should  be changed. That's rather a question for the WELD guys.

                  • 6. Re: Registering transaction synchronization during time of beforeCompletion
                    tomjenkinson

                    ochaloup  wrote:

                     

                    tomjenkinson  I'm seeking through the specification but I don't understand what part of the specification you mean. For my better understanding what part do you refer to, please?

                     

                    I see what you mean now. You are suggesting to allow the registration of a session synchronization with the full knowledge it's before completion will not be called. The relevant bits of the specification to my mind are:

                     

                    * registerSynchronization throws IllegalStateException: Thrown if the transaction in the target object is in prepared state or the transaction is inactive.

                    Although we can't solely use the description in the throws statement as justification, when in combination with the following statements I think it is justified

                     

                    * Definition of the session synchronization: The transaction manager invokes the beforeCompletion method

                    * Definition of registering an interposed synchronization: Its beforeCompletion will be called after all SessionSynchronization beforeCompletion callbacks

                     

                    So in that sense by permitting a registerSynchronization you would be breaking contracts for the other synchronization statements.

                    • 7. Re: Registering transaction synchronization during time of beforeCompletion
                      ochaloup

                      tomjenkinson hm, ok. But still, I don't understand what part of the spec my proposal breaks. Here is how I understand the points.

                       

                      * registerSynchronization throws IllegalStateException: Thrown if the transaction in the target object is in prepared state or the transaction is inactive.

                      Although we can't solely use the description in the throws statement as justification, when in combination with the following statements I think it is justified

                      At time the beforeCompletion method is called the transaction is not either in inactive state nor in prepare state. We are at state of either running or preparing (beforeCompletion is called before transaction is about to start 2PC, see narayana/TwoPhaseCoordinator.java at master · jbosstm/narayana · GitHub ).

                       

                      * Definition of the session synchronization: The transaction manager invokes the beforeCompletion method

                      * Definition of registering an interposed synchronization: Its beforeCompletion will be called after all SessionSynchronization beforeCompletion callbacks

                      There is said that beforeCompletion of the interposed synchronization is invoked after all the other beforeCompletion synchronizations are called. But why I can't to register for afterCompletion invocation. There is no such contradiction. There is not said that both synchronizations (before and after) have to be called.

                      In fact I think these sentences support my point of view. You are not permitted to call the beforeCompletion of the SessionSynchronization after interposed synchronization. That's why I skip to call it. But I can still benefit from fact that my synchronization will be called at afterCompletion.

                      What do you think?

                      • 8. Re: Registering transaction synchronization during time of beforeCompletion
                        tomjenkinson

                        ochaloup  wrote:

                         

                        tomjenkinson  hm, ok. But still, I don't understand what part of the spec my proposal breaks. Here is how I understand the points.

                         

                        * registerSynchronization throws IllegalStateException: Thrown if the transaction in the target object is in prepared state or the transaction is inactive.

                        Although we can't solely use the description in the throws statement as justification, when in combination with the following statements I think it is justified

                        At time the beforeCompletion method is called the transaction is not either in inactive state nor in prepare state. We are at state of either running or preparing (beforeCompletion is called before transaction is about to start 2PC, see narayana/TwoPhaseCoordinator.java at master · jbosstm/narayana · GitHub ).

                         

                        * Definition of the session synchronization: The transaction manager invokes the beforeCompletion method

                        * Definition of registering an interposed synchronization: Its beforeCompletion will be called after all SessionSynchronization beforeCompletion callbacks

                        There is said that beforeCompletion of the interposed synchronization is invoked after all the other beforeCompletion synchronizations are called. But why I can't to register for afterCompletion invocation. There is no such contradiction. There is not said that both synchronizations (before and after) have to be called.

                        In fact I think these sentences support my point of view. You are not permitted to call the beforeCompletion of the SessionSynchronization after interposed synchronization. That's why I skip to call it. But I can still benefit from fact that my synchronization will be called at afterCompletion.

                        What do you think?

                        If you don't call the beforeCompletion at all then it would contradict this statement, would it not?: "The transction manager invokes the beforeCompletion method prior to starting the two-phase transaction commit process"

                         

                        Some other statement: "Its beforeCompletion will be called after all SessionSynchronization beforeCompletion callbacks" (here I would say "all SessionSynchronization beforeCompletion callbacks" would be contradicted.

                         

                        From: Synchronization (Java(TM) EE 7 Specification APIs) : "The beforeCompletion method is called by the transaction manager"

                        • 9. Re: Registering transaction synchronization during time of beforeCompletion
                          ochaloup

                          tomjenkinson Agree, there is some slight contradiction here : as "all SessionSynchronization beforeCompletion callbacks" but as I won't call the beforeCompletion of the newly added synchronization then I can make it true. I think the sentence could be understood in different ways it could easily to be understood as "all SessionSynchronization beforeCompletion callbacks of range of the eternity" or in the same way it could be ""all SessionSynchronization beforeCompletion callbacks known at the time it's triggered".

                           

                          Agree, the point that TM invokes beforeCompletion prior the 2PC is the most legitimate - for me. Despite it if you as user decide  to register synchronization callback at the end of the beforeCompletion phase you take responsibility of understanding that the beforeCompletion won't be called. It won't restrict you in any way as at time of registration you are already in scope of the beforeCompletion time and any action you need to process at that time can be invoked directly without providing the code into the synchronization.

                           

                          Personally I can see benefits in adding this type of handling. I can't see the specification would say this is something that can't be handled the way I propose. I fully understand that you are not in favour of this idea as I am. If you are strongly against then let's leave it as it is. I don't have more arguments with me

                          • 10. Re: Registering transaction synchronization during time of beforeCompletion
                            smarlow

                            We know that its too late to register a session sync, for the session sync before completion callback to be called but we don't really know if that is an error condition, as the application could really just want the session sync after completion to be called.  This does seem like a hole though.

                            I agree that if CDI could allow the application code (I think in this case, the JPA entity listener callback) to express that an interposed synchronization should be used, instead of a session synchronization, that could be one solution to this situation.   It would be interesting to hear thoughts on that from the CDI team. 

                            • 11. Re: Registering transaction synchronization during time of beforeCompletion
                              smarlow

                              ad PSS: I do not agree with the reporter that this is the correct solution. I agree with him in the point that change of the CDI specification would solve this problem. But I'm unsure if the spec change is what could be called the good solution. I mean in way if this is the place where the specification should  be changed. That's rather a question for the WELD guys.

                              I agree, although, I think the application should be able to choose between interposed/non-interposed, depending on when application code is expected to be invoked.

                              • 12. Re: Registering transaction synchronization during time of beforeCompletion
                                tomjenkinson

                                ochaloup  wrote:

                                 

                                Personally I can see benefits in adding this type of handling. I can't see the specification would say this is something that can't be handled the way I propose. I fully understand that you are not in favour of this idea as I am. If you are strongly against then let's leave it as it is. I don't have more arguments with me

                                Well, I could see a ways to take it forward (if that is the preference of the wider community):

                                1. A jta-spec clarification (Mailing List Archives - jta-dev | The Eclipse Foundation  and jta-spec@javaee.groups.io | Topics ) is made

                                2. We make a configurable option in Narayana implementation

                                3. We add a special interface into the SPI that indicates it is a synchronization which does not have a beforecompletion implementation and Weld is changed to use it

                                 

                                One thing I am considering is whether a situation could arise where someone could register a session synchronization which does have a beforeCompletion and does not realise that it's beforeCompletion will not be called - is that possible?

                                • 13. Re: Registering transaction synchronization during time of beforeCompletion
                                  ochaloup

                                  smarlow I'm not sure if it's safe to allow user to work with the interposed synchronization. From what I understand the WFLY needs to control the ordering of interposed synchronization callbacks (wildfly/JCAOrderedLastSynchronizationList.java at master · wildfly/wildfly · GitHub ) and allowing user to easily add interposed synchronization could break whole the thing. Or could not?

                                  On CDI - I think the way how CDI can work with this is well summarized in [CDI-724] Transactional observers fired in inconsistent manner when synchronisation cannot be placed

                                   

                                  tomjenkinson

                                  1. this sounds reasonable to me. if the specification would say that beforeCompletion would not be called in case you register callback too late then the issue is solved.

                                  2. that would be a quick and easy way, agree

                                  3. that could be fine as well if CDI would not have trouble to use the narayana SPI. User then utilize only the interface with the afterCompletion callback and he declares that he intentionally wants the handling and he understand the beforeCompletion won't be called

                                  • 14. Re: Registering transaction synchronization during time of beforeCompletion
                                    tomjenkinson

                                    Perhaps we could bridge options 2 and 3 by allowing the user to provide a list of synchronization classnames (via configuration) that only contain afterCompletion and should be allowed registration at any point prior to 2PC?

                                    1 2 3 Previous Next