It sounds like everything is as it should be. Maybe you just had incorrect 
assumptions about how this was supposed to work? In other words, is it possible 
the problem isn't with the design? I don't know about the code, I won't comment 
on that.

In any case, are you saying that if something is triggered by an already 
established commit or rollback that a service triggered by it should be able to 
modify that somehow? What would be the point of trying to work in the context 
of a transaction that is already in the process of being committed (I think 
this happens between phases 1 and 2 of a 2-phase commit, if I remember right) 
or rolled back? Wouldn't it be a bad idea to do anything with that transaction?

As fun as writing is, it's amazing how much more productive reading can be.

-David


On Apr 16, 2010, at 11:51 AM, Adam Heath wrote:

> So, the service engine has this way cool feature, the ability to call
> a service when the current transaction is rolled back, or committed.
> However, in reality, it actually is completely and uterly broken.
> 
> Both of these methods allow for persisting the job to the JobSandbox.
> That in itself is not a problem.
> 
> What is a problem, is that GenericAbstractDispatcher will *always*
> make any such registered service an async service.  There is no way to
> run a sync service.  Remember this point, I'll come back to it in a bit.
> 
> Once the ServiceXaWrapper is registered with the transaction, and the
> actual commit/rollback phase happens, it'll end up calling an internal
> runService helper method.  However, this helper method is run inside a
> brand new, temporary thread.  This effectively makes *all* registered
> services async.  That's just broken.
> 
> One thing I'm not familiar with, is if a thread that spawns a new one
> automatically inherits the parent thread's transaction.  However, no
> matter what that scenario actually is, when runService is running in
> its own separate thread, it suspends the parent transaction.  This
> means it's in its very own separate transaction.  So that the service
> actually being run will *not* see anything that was in the original
> transaction upon which it was registered.
> 
> Now comes the time to actually run the real service.  Since the
> service is always an async service, it'll be serialized to JobSandbox,
> and run a very short time later.  Not immediately.
> 
> Back in the original, parent thread, service, and transaction, the
> transaction is committed or rolled back.
> 
> The aforementioned async service(s) are now run.  If the transaction
> was rolled back, and they try to manipulate data, the original data
> will no longer exist.  So, the service will fail, and the JobPoller
> will schedule a retry of the service.  But, the service never has a
> chance of succeeding, so this will repeating ad infinitum.
> 
> I was able to track all this down, because we had
> placeOrder/processPayment run inside a transaction, that was then
> aborted if the payment was declined.  We then started getting spammed
> in the log with failed sandbox entries.
> 
> Does anyone else agree with my reading of the code?  Just looking at
> the source I was able to discover these very poorly implemented designs.
> 
> 
> Does anyone else agree with my reading here?

Reply via email to