47
Views
4
Comments
Solved
Transactions between reactive and traditional apps
Application Type
Traditional Web, Reactive
Platform Version
11.22.0 (Build 39859)

Hey everybody,

There's something strange happening in my customer's reactive apps. We've been converting the UI of their old traditional apps to reactive.
We separated all the logic and DB access in modules so we could reuse many of their old traditional server actions in the new reactive app. But it seems that sometimes a bug happens that makes part of the server transaction to rollback, but not all of it.

Allow me to clarify. Imagine this scenario:
- the Reactive App calls a server action in Reactive module "Rm1";
- Rm1's action executes a series of other server actions, in this order:

1- action "TransitionState" which exists in an old traditional web module and returns the expected output with no errors. This action creates a few records in 2 different entities;
2- action "SaveRecord" which exists in a new reactive module (let's name it "Rm2"), which also returns no errors. This action updates the main record in the DB with values returned from action "TransitionState";
3- action "NotifyPeople" which exists in an old traditional web module and returns no errors. This action saves information returned by the "TransitionState" action on an entity named "MailOutput". Then, a wake timer is called and that timer reads the "MailOutput" entity to see if it has some emails that weren't sent yet. If it has, it sends them. Since this is an old traditional module, it still uses the "old way" of sending emails: RichMail. If the email is sent with no errors, it updates the "MailOutput" entity marking that record so the timer won't send it again.


This is all very simple logic, but sometimes step 2 seems to not happen (rolled back somehow) and no error is displayed in the error logs (all exception catchers have the log error property to YES). Step 1 is commited to the DB and step 3 also commited because we can see the entity "MailOutput" with the correct values and the respective users got the emails sent by the timer.

The only clue we have is something that happens consistently everytime this bug manifests: there's some kind of delay in the DB that causes the slow warning in the general logs:

Entity Action CreateOrUpdateMainRecord (update) took 4015 ms -> 4 seconds is too much time to be spending on an update that usually isn't even showed in these logs (this is executed in step 2)

Entity Action UpdateMailOutbox took 4047 ms -> 4 seconds is too much time to be spending on an update that usually isn't even showed in these logs (this is executed in the timer that is awaken in step 3)

RichMail.RichMailSend took 610 ms -> this one isn't too bad (this is executed in the timer that is awaken in step 3) 

This has happened in other apps not exactly like this but similar and it seems to always involv the use of the RichMail. When I remove the sending of emails the problem never happens again. I even tried to use a CommitTransaction but with no luck. To make thinks worse, this is an intermitent problem even with an exact replica of the records being saved by the user. So, the users can execute the main action 100 times with the same set and this works fine 99% of the time.

As something like this ever happened to anyone? Just trying to bounce some ideas off of the community.

regards

2018-11-09 09-14-06
Gonçalo Almeida
Solution

After many battles I found out that this is happening because sometimes the user is double clicking buttons, which submits 2 transactions in a row and the 2nd was changing data that was saved from the 1st one. I've added logic to prevent this.

2023-02-20 05-20-57
Nam Nguyen

Hi, 

Reactive and traditional use database transaction.

It happens due to the table-lock mechanism. You're executing multiple operations on a record in separate transactions. The proof is Entity Action took a long time to execute
 

I believe RichMail is not the problem. Rm1's action is used in the End-User module, which means if many users trigger simultaneously -> WakeTimer will be activated simultaneously, and records will be updated simultaneously, including the same record being executed in the previous timer.  Lead to the issue I mention: table-lock. "UpdateMailOutbox took 4047 ms"

I had a similar issue before. To resolve it,  use CommitTransaction. 

May I ask where you use the CommitTransaction action in your flow? 
I think you're missing somewhere.

Cheers,
Nam


2018-11-09 09-14-06
Gonçalo Almeida

Hello,

The CommitTransaction was right after stage 2. But it was only for testing purposes because if somehow there's an error in stage 3 I can't rollback the other ones.

If what you say is true then perhaps I shouldn't trigger a wake timer and simply set a different schedule for the timer and let it run every 10 minutes, for example.

2023-02-20 05-20-57
Nam Nguyen

Hi,

CommitTransaction should be placed after the Create/Update operation.

If you set a different schedule for the timer, it will solve the "UpdateMailOutbox" operation log.

The "CreateOrUpdateMainRecord" log may not.

Cheers,
Nam






2018-11-09 09-14-06
Gonçalo Almeida
Solution

After many battles I found out that this is happening because sometimes the user is double clicking buttons, which submits 2 transactions in a row and the 2nd was changing data that was saved from the 1st one. I've added logic to prevent this.

Community GuidelinesBe kind and respectful, give credit to the original source of content, and search for duplicates before posting.