An asynchronous singleton processing component?
fraktalek Oct 15, 2009 7:24 PMHi, I'm trying to solve the following problem, to no end so far... I'm still quite new to Seam and Java EE so I might be overlooking the solution.
Clients produce data which I need to process sequentially and asynchronously. Asynchronously because the processing may take a long time and clients can't be forced to wait until it's done. Sequentially because there are interdependencies - if two update tasks ran concurrently then something might be missed. The order is not so important though.
The updates need not be persistent - in case of a server crash there is a way of computing what might have been missed but it would be quite costly which is why I can't use it for incremental online processing.
So, when it comes to asynchronicity, Seam seems to offer asynchronous events (catched via @Observer), messaging with JMS and MDBs, and the timer service.
I don't think I can use asynchronous events because first I would have to make the @Observ-ing method synchronized which is something I shouldn't do in a JavaEE environment, right? And second, even if I made it synchronized, the processing of one update may take a long time, definitely and easily longer than the default synchronized timeout (1000ms) and it just doesn't seem correct to set the timeout to some big number (it's almost impossible to estimate the upper bound of the processing time, if there is some).
Because I can't estimate the processing time I can't really schedule the updates using a timer service. And I don't want to persist them and run the timer in regular intervals to check if there is some update pending because it could hinder performance (some updates may take a long time, but I think that usually it will be quite fast).
The problem with JMS and MDBs is that MDBs are meant for concurrent processing which is something I do not want. I want to process the updates serially and there doesn't seem to be any clean way of imposing this constraint on an MDB.
So I thought of using JMS without MDBs - create a JMS Queue, one Seam POJO component as a JSM producer, another Seam POJO component as a JSM consumer. I am not using MDBs so I can be sure about the number of threads that are used (possibly many for producers, but only one consumer) and because it is POJOs I can be sure that the container won't create instances as it likes, right? (as it would in the case of MDBs)
This kind of works, but unfortunately only kind-of. The problem is probably the call of the consumer's onMessage() method which seams to be outside of application context so injection of entity manager does not work (entity manager is null and if I try to get it via entityManager = (EntityManager) Component.getInstance("entityManager") then I get an IllegalStateException that there is no active application context (if I remember correctly, sidenote: I made both the producer and consumer an application-scoped seam component). So one question would be how to get my hands on entityManager from inside of onMessage()? A JNDI lookup of EntityManagerFactory? But this probably would not be sufficient anyway because from the onMessage I need to call other Seam components which do the actual processing (and to do that they use the database heavily). How comes that there's no active application context? I assume that it's because of the asynchronous call made by the JMS provider (JBoss) but isn't this a "bug" in Seam? I can inject seam components in MDBs, right? So why shouldn't it be possible in a simple JMS consumer?
I think this can't be so uncommon use-case so how is it usually solved? Thanks in advance for any insight.
Clients produce data which I need to process sequentially and asynchronously. Asynchronously because the processing may take a long time and clients can't be forced to wait until it's done. Sequentially because there are interdependencies - if two update tasks ran concurrently then something might be missed. The order is not so important though.
The updates need not be persistent - in case of a server crash there is a way of computing what might have been missed but it would be quite costly which is why I can't use it for incremental online processing.
So, when it comes to asynchronicity, Seam seems to offer asynchronous events (catched via @Observer), messaging with JMS and MDBs, and the timer service.
I don't think I can use asynchronous events because first I would have to make the @Observ-ing method synchronized which is something I shouldn't do in a JavaEE environment, right? And second, even if I made it synchronized, the processing of one update may take a long time, definitely and easily longer than the default synchronized timeout (1000ms) and it just doesn't seem correct to set the timeout to some big number (it's almost impossible to estimate the upper bound of the processing time, if there is some).
Because I can't estimate the processing time I can't really schedule the updates using a timer service. And I don't want to persist them and run the timer in regular intervals to check if there is some update pending because it could hinder performance (some updates may take a long time, but I think that usually it will be quite fast).
The problem with JMS and MDBs is that MDBs are meant for concurrent processing which is something I do not want. I want to process the updates serially and there doesn't seem to be any clean way of imposing this constraint on an MDB.
So I thought of using JMS without MDBs - create a JMS Queue, one Seam POJO component as a JSM producer, another Seam POJO component as a JSM consumer. I am not using MDBs so I can be sure about the number of threads that are used (possibly many for producers, but only one consumer) and because it is POJOs I can be sure that the container won't create instances as it likes, right? (as it would in the case of MDBs)
This kind of works, but unfortunately only kind-of. The problem is probably the call of the consumer's onMessage() method which seams to be outside of application context so injection of entity manager does not work (entity manager is null and if I try to get it via entityManager = (EntityManager) Component.getInstance("entityManager") then I get an IllegalStateException that there is no active application context (if I remember correctly, sidenote: I made both the producer and consumer an application-scoped seam component). So one question would be how to get my hands on entityManager from inside of onMessage()? A JNDI lookup of EntityManagerFactory? But this probably would not be sufficient anyway because from the onMessage I need to call other Seam components which do the actual processing (and to do that they use the database heavily). How comes that there's no active application context? I assume that it's because of the asynchronous call made by the JMS provider (JBoss) but isn't this a "bug" in Seam? I can inject seam components in MDBs, right? So why shouldn't it be possible in a simple JMS consumer?
I think this can't be so uncommon use-case so how is it usually solved? Thanks in advance for any insight.