I try to do the following:
A client calls a Stateless SessionBean QuoteService to make a quote. This stateless sessionbean looks up (with the help of some sessionbeans/entities) which companies are configured to make a quote. It wants to send to each of them a request, at the same time, and then merge the responses and send those back to the client.
From here I tried several approaches: the specific company services each in a separate sessionbean. The QuoteService starts a thread for each of them and collects the results. If some of them don't respond, the threads are cut off after a timeout. This approach failed. As I read as well, one shouldn't start threads inside a sessionbean. For one concurrent QuoteService call it all went well, but with several concurrent users at the same time, the new threads seemed to be waiting on each other/started sequentially instead of parallel-wise. Besides, suddenly the pooling to the other entity/session beans did not work any more. No threads thus.
Then I read on the forum that one should create Message Driven Beans for each specific company service to be called, and let the QuoteService start them by sending a message to each of them. That will work. But how do I get the results back? I tried to implement a response queue and let the sessionbean wait with receiver.receive. Only, I don't know how many results I will receive in the end and again have to cut off after a certain time.
Choosing the receiver.receive() method is dangerous. What if none comes back? And when I sent three messages, should I call receive three times?
Choosing receiver.receive(30000) would maximally wait 30 seconds. But here again I am introducing threads and as described above, with concurrent users this is not going to work. Besides how to get three messages returned?
QueueRequestor seems to be nothing else than a kind of helper class that also contains a receive method ...
So far I don't know how to let a sessionbean wait for a maximum time and let it receive all messages that are replies on its own originating outgoing messages ..
Maybe this can only be done on the client side? That would be a pity, as I would love to hide this functionality for clients.
So far I can only think of:
let quoteservice send messages to all companies, and then return a unique id and a number of messages back to the client.
Let the client wait for the response queue with a message selector using the unique id, and either retrieve all messages, or wait a maximum time.
I don't like this at all, much too mcuh functionality on client's side :-(.
Hope someone can steer me in the proper direction.
This type of processing is generally doomed to failure
for a number of reasons.
If none of the following apply to your use case,
you might be able to make it work.
1) Each new "thread" of work you start cannot take part
in the same global transaction. The transaction can
only be attached to a single thread at a time.
2) If one unit of work fails there is no way to stop
the other threads running to completion.
3) It doesn't scale.
3a) If you naively start new threads for each request
you very quickly run out resources under heavy load.
3b) If you implement it as a queue, the queue will at
some point not be able to keep up the work unless you
let it approach something like the 3a behaviour.
4) If the processing is not independent for each unit
of work, each unit of work will serialize on some
point of contention (e.g. an entity bean lock)
5) The coordinator (in your case a session bean) will
tie up resources while it does no work - it is just
waiting. If there is a transaction associated with
the session bean invocation it may timeout before
you get the response.
Although JMS appears to allow multi-threaded behaviour in
a j2ee server, it is actually meant for asynchronous
processing. i.e. Some work that needs doing at some
point but you don't need it completing before you
return to the client.
A typical example is sending an e-mail confirmation
for an order, or printing the pick-list in the warehouse.
It does not matter that these are not done immediatley.
Depending upon your client, it would probably appreciate
displaying the quotes as they arrive. That way the user
can view some of the quotes rather than waiting
for the slowest common denomitator. :-)
thanks for your detailed answer. I have just reread it three times and let's see whether I understand it.
My case is not a asynchronous processing problem, but more a multithreaded problem. Wherever I will put the multi functionality, I will still need the ability to make several quote calls for a client at the same time.
In that way, for 50 clients for instance, quoting with four companies, that would create 200 concurrent calls (50 per company).
Now jboss doesn't like to do multithreading inside sessionbeans. Thus I see two options:
1: client calls sessionbean to find out which companies are available for quoting (this must be dynamic). Session bean returns an array of jndi-name, remote-home interface type, remote type per company and client can starts a thread to call each of them. So now the multithreading has moved from ejb container to client. Still there is a risk of thread overuse. Some sort thread pooling may need to be implemented on client side.
2. session receives request and sends a message with unique sessionbean/client id to each of the companies. The company services are implemented as mdbs and send their result back to a common topic/queue. Meanwhile the session bean terminates and returns the unique id and the number of companies to the client.
The client starts a messagelistener to the common queue with a message selector on the unique id. Either when time has passed by,or when all company reply messages have arrived, the client will merge all the results and show them to the enduser. In this way, I don't need extra threads, but do need to implement messages and accept a bit of performance overhead for that.
Is my summary correct?
What is the preferred way of implementing this?
Ok now we have some numbers (50 concurrent clients).
The naive approach takes 250 threads.
50 session beans and 50x4 threads to service the requests.
The MDB approach takes less
50 session beans and 4xMDBPoolSize (default 15)=60
plus some other threads used internally by JMS for
Sending the MDB reply to the client would be even better.
The session beans can submit the requests and return,
each client waits for the responses from the company MDBs.
But this requires 50 socket connections to
handle the message delivery to the clients and puts
some added complexity on the client.