Page 1 of 1

Transaction handling and unsolicited events

Posted: Fri Aug 07, 2009 11:39 am
by ConvertFromOldNGs
by Theodore Taptiklis >> Thu, 3 Dec 1998 2:36:32 GMT

I have discussed with various people how best to handle unsolicited events so that they don't conflict with existing activities within a process,
particularly with regard to transaction state inside JADE.

When using Timers and Notifications your application can get an unsolicited event which you deal with. If in this event (timerEvent, sysNotify or userNotify) you have code that needs to go into transaction state (beginTransaction or beginLoad) then there is a possibility of conflict with the rest of the application. The application could already be in transaction state and you will receive an exception. If I handle the exception and ignore it then I need to decide who should issue the end of the transaction (endLoad, commitTransaction, abortTransaction).

I am interested in hearing how people handle this issue.


Theo

Re: Transaction handling and unsolicited events

Posted: Fri Aug 07, 2009 11:39 am
by ConvertFromOldNGs
by Craig Shearer >> Thu, 3 Dec 1998 20:19:03 GMT

Hmmm... this is always a thorny problem....

You can do something like the following...

vars
beganTransaction: Boolean;
begin

if not app.isInTransactionState then
beginTransaction;
beganTransaction := true;
endif;

// perform the stuff inside your transaction here

if beganTransaction then
commitTransaction;
endif;

end;

however, it is very easy to sprinkle this code in undesirable places, meaning that you will have the problem of multiple transactions, allowing your application to leave your database in an inconsistent state should the system fail at some inappropriate time - hardly a robust solution.

Actually, the problem you describe isn't nearly as common as you think. Your application won't ever receive a notification inside a transaction (or any other method, for that matter) unless you let it. In order for a sysNotification or userNotification method to execute, you would need to have a app.doWindowEvents call inside your transaction code - this seems like bad design to me. To clarify, once a method is executing, it won't be interrupted by a notification or a timer event.

You should be writing your applications so that your transactions are short lived. If you have a need to have long transactions, then you really need a mechanism that allows you application to clean up in case of failure at some critical point, or you need to do stuff using transients, then update the database in a short transaction when you're ready.

Re: Transaction handling and unsolicited events

Posted: Fri Aug 07, 2009 11:39 am
by ConvertFromOldNGs
by Krull McSkull >> Thu, 3 Dec 1998 21:11:21 GMT
I have discussed with various people how best to handle unsolicited events so that they don't conflict with existing activities within a process,particularly with regard to transaction state inside JADE.

When using Timers and Notifications your application can get an unsolicited event which you deal with. If in this event (timerEvent, sysNotify or userNotify) you have code that needs to go into transaction state (beginTransaction or beginLoad) then there is a possibility of conflict with the rest of the application. The application could already be in transaction state and you will receive an exception. If I handle the exception and ignore it then I need to decide who should issue the end of the transaction (endLoad, commitTransaction, abortTransaction).



Hmmm, I seem to recall this same question arose on a JADE list some time ago. It is a good question that gets raised quite a lot and I just happen to have my previous list response to this issue, the following is an abridged version of the response:

There are a number of issues to be considered:

If we allow an unsolicited event such as a timer or notification event to be actioned in a process, that is still actioning some other event, then it becomes a nested action. If the process is already in transaction state and the incoming unsolicited event also updates the database, then we have the additional complexity of a nested database transaction to deal with. The most obvious problems with handling this inolve transaction failure scenarios:

a) If the outer transaction aborts after the nested event has been processed, then it will undo the effects of the nested transaction.
b) If the nested transaction aborts, then it will undo the effects of the outer transaction leaving the process out of transaction state; in addition, the next updating operation will encounter an exception.

Neither of the above scenarios is desirable and either one would be very complex to handle in application logic.

There are also some not so obvious problems to be aware of:

Any nested event-action has visibility to the effects of the transaction in which it is nested, but the outer transaction could be incomplete.This means that the nested action will 'see' an inconsistent database state, and further the state it ' sees ' may vary depending on what points it starts processing within a given transaction and what transactions permit nesting to occur. A general aim of database transaction processing is that overlapping transactions should not interfere with each other. That is, the net effect (to the database) of processing transactions in an overlapped fashion should be identical to the results achieved if they are processed one after another in a serial fashion.

It is clear that if we allow nested transactions to occur when processing unsolicited events then the nested transactions are in general not serialisable and the effects could be unpredictable.

Note: this issue is not just limited to the case with the nested event-action is updating. A read-only transaction that has internal or external side-effects could produce non-repeatable and/or incorrect results if the side effects are based on uncommited database state.

The next consideration is that timer or notification driven database update logic could potentially be developed in isolation to user
interface logic, possibly by different people. There are number of ways in which an application give up control allowing unsolicted events to be processed. These include, use of msg boxes, modal dialogs, Application::doWindowEvents - an unhandled exception dialog or user exception dialog for instance are candidates. In a complex system it will rapidly become very difficult to consider all possible combinations and interactions of updating event-actions; it will be even more difficult to test all the potential interactions.

So how do you avoid this complexity?

I think the simplest way, right now is to dedicate a background application/thread to processing any unsolicited timer or notification events which update the database. It is a simple matter to arange that these event-actions in themselves never give up control and are therefore processed serially. There are of course notifications (and timers) which by the nature must process within the application controlling the user interface. These are generally notifications used to synchronise the user interface with the database or timers that are doing some sort of animation with the UI.

In summary I would make the following two recommendations:

1) Avoid the problem alltogether - *NEVER* allow unsolicted events which update the database to be nested within existing transactions.

2) If a notification or timer event-action is allowed to be nested, then any side effects of processing the nested event should not be based on persistent database state. The side effects should be based entirely on the event itself and/or parameters passed to the callback method. This will avoid side-effects based on partial or inconsistent database state.

Cheers
'Skull