|
started a thread on the EJB3.0 forums -- http://www.jboss.com/index.html?module=bb&op=viewtopic&t=133754
r678 - add private scope to all injected SLSB references
r679 - remove unused @EJB injection; remove @IgnoreDependency on self-reference, as this does not cause a cyclic-dependency issue during deployment; r680 - remove all other instances of unused @EJB injections in the server/jar module, this will reduce/simplify the deploy-time dependency graph; rev684 - simple graph analysis showed that we are using @IgnoreDependency too generously;
take out some unnecessary uses of it, and moves some others around (to change where we break the circularity); rev690 - missed one new @IgnoreDependency annotation that resolves the SLSB dep graph;
|
||||||||||||||||||||||||||||||||||||||||||||||||
The only ordering guarantee that the deployer gives us is that services with dependencies -- and @EJB creates an implicit dependency -- will have their deps started first. Our problem is that our SLSB layer has many cycles in the dep graph, and we break those cyclic dependencies via the use of (at the date of this writing) 23 instances of @IgnoreDependency.
Unfortunately, if there are messages in the queue at startup, then the MDB is apparently started early in the deployment of the EJB module. Here is the sequence of events that are failing us.
MDB -> A -> B -> @Ignore...C -> D -> B
Notice the cycle between B, C, and D. B needs C to be started, C needs D to be started, and D needs B to be started. When those services were developed, no attention was paid to which service got the @IgnoreDependency annotation affixed to it, but because the MDB now wants to process messages, *it* will initiate other service starts by following its dependency graph.
Clearly, when the deployer gets to service B, it notices that it can ignore the dependency on service C, and it does. However, when the deployer is done doing its job and hands control back over to the MDB, some of the needed downstream services aren't in the started state.
It picks the next message from the queue, and the MDB interacts with A, and A interacts with B, and when B tries to interact with C -- boom. The EJB container complains that the B.referenceToC has not been initialized / is not a valid reference / etc.
One solution to this would be to simply move the cyclic dependency downstream from the MDB caller. If the dep graph had looked like:
MDB -> A -> B -> C -> D -> @Ignore...B
Then things would have "just worked." In this scenario, even though B isn't explicitly started as a dependency of service D, it *will* be started before control is passed back to the MDB. D finishes and is put in the started state, which allows C to start, which allows B to start (ah, see, we didn't need to start B further downstream, because it was already on the path), which allows A to start, and finally control is passed back to the MDB. This time, when the MDB picks a message off the queue, all necessary downstream services are started correctly.
However, there's one big issue with this solution. If over the evolution of your service layer, you add more and more MDBs, then you need to make sure that *all* of them abide by this rule. Unfortunately, there can (and will) be instances where different MDBs share some of the same downstream dependencies, and therefore will have mutually exclusive solutions using this rule. In other words, if you fix one dependency chain, you break another, and vice versa.