When a
RuntimeException is thrown during the execution of a command, the prevalent system enters an undefined, potentially inconsistent state.
"You will now have the means to actually write server code. It is the way object orientation was intended all along; but it is certainly not for wimps." --
PrevalenceSkepticalFAQ
It is clear that the quality requirements for prevalent server code are much higher that those for flaky client code. Although
RuntimeExceptions are expected to be extremely rare, we must have some way of dealing with them.
KlausWuestefeld
A few directions some people started to explore:
#Using rollbackable "variables" and collections. See
RollbackSupport.
#Halting all commands and queries while
Prevayler recovers the last snapshot an applies the commands.
The first idea would be almost like using an OODBMS. The main impacts will be on simplicity, transparency and performance.
The second idea would have an impact on availability, unacceptable for many systems.
More ideas? --
KlausWuestefeld
This morning, while I was in the bathroom, a possible solution to this problem was given to me.
Basically, we can apply each command to the replicas only after it has executed successfully in the "hot" system, without throwing a
RuntimeException. When a
RuntimeException occurs, the "hot" system restarts and the replica takes over.
Of course, you will still have the same availability problem (waiting for restart) if your code throws so many
RuntimeExceptions that your replicas cannot keep up.
Every
RuntimeException will still have a cost but, it is no longer required that your code be 100%
RuntimeException free. @;) --
KlausWuestefeld
Could a similar technique be used to maintain availability during a snapshot?
I think the whole
RuntimeException argument boils down to the problem of HighAvailability. Where an
RDBMS uses specialized hardware, limited operations, and rollback to get HighAvailablity,
Prevayler uses redundancy, assuming the occasional crash is inevitable.
DarrinThompson
It looks like a forced solution to a problem wich could have a simplier one. Transactions are not something we must be afraid of! Sometime ago, Klaus and I, after a huge discussion on prevayler list (the portuguese one), agreed that prevayler in fact has transactions, but in a very special way. So my point is:
1)How does prevayler deal with a command that was written to disk and during its execution a RuntimeError (out of memory, Esgrinphos atacked, ...) occurs?
By your solution the replica server would not be aware of this command and therefore, prevayler would reestart and be doomed to restart ab aeterno, because the client would resend the command again and again since the error is not his.
2) What is the big deal with creating a Transaction class that each instance of it is treated exactly as a command, and therefore when a exception occurs all it's done is wiped?
EmilioFrancesquini
PS. Please try to convince me, but so far I don't think the absense of transactions is a marvelous thing as you preach
Some thoughts:
I thought reading some specifics would be helpful. So I checked the Javadocs for JDK 1.4 and looked up
RuntimeException. The list of classes that extend it is disconcerting. Looks like a lot of stuff that really could happen, and really could doom a prevayler cluster.
Maybe that's Java's way of saying "Yes, there are bad commands."
What if we do what Klaus suggested but not actually pass the command on to replicas until it's safe?
[oops duh, that's what he said.]
Wouldn't a network protocol tell the client that the command it sent was bad? I don't think that anything but a malicious client would retry after it was told that it's command was rejected for a "
RuntimeException" reason.
I like Klaus' idea because it's provably correct. The only problem with it is that it opens up a method for attack by a malicious client sending a lot of bad commands. I don't want to implement "undo" methods because I know I would sooner or later mess one up. That opens up the possiblity for the system to go into an inconsistent state silently.
DarrinThompson
Prevayler does have transactions, as Emílio ponted out, and as we can read from the TheFAQ (
DontINeedTransactions?):
"In the prevalent design, every transaction is represented as a serializable object which is atomically written to the queue (a simple log file) and processed by the system. An object, or object graph, is enough to encapsulate the complexity of any business transaction."
What Prevayler does
not have is:
#
RollbackSupport
#
DoItYourselfTransactions
I have, therefore, moved the discussion that was in
TransactionSupport to
RollbackSupport.
KlausWuestefeld