Discussions

J2EE patterns: Asychronous Multiple Load Processes

  1. Asychronous Multiple Load Processes (10 messages)

    You can go and visit the pattern here ASYNCHRONOUS MULTIPLE LOAD PROCESSES

    Context:
    This pattern proved better performance results over the synchronous reading and processing of data. This pattern is best suited for loading of data from file, database etc.,

    Problem:

    When doing a multiple data processing from client to remote server, the conventional way of processing information is to first look up the bean's home object, obtain its remote reference then with each record to process make a remote method call to send the value objects to the server for processing. Until the server is done with the process the client will not be able to send the second record of data to the server.

    This can be reduced to some extent when using multiple loads running in different threads where in the server will be able to receive multiple requests and process the load simultaneously before the first client prepares for the next call thru the network.

    It is obvious that lot of time is taken for the to and fro remote call to the network. It’s more essential that the business process remains the same irrespective of the type of call (i.e. from mass or bulk load process or the normal transactions). Since for mass loads the results are not expected back to the client on record-by-record basis, we can avoid the two-way network call and make this one way. However a detailed report on the mass load processing results should be created at the server side.

    Forces:

    This calls for a design, which can have a loosely coupled asynchronous way of communication between the client and the server. This can avoid both the client and server for each other’s presence.

    To have a mechanism, which is portable, robust, transaction aware, asynchronous, distributed for the mass data processing from the client.

    Solution:

    To make the efficient usage of both the client’s and the server's processing time, a new way of communication is established which is an asynchronous loosely coupled way of loading the data. This could be achieved by using the Message Driven Beans from the new EJB2.0 specification. This new type of Enterprise Java Bean (EJB), which closely interacts with JMS, greatly facilitates the building asynchronous J2EE applications. This newly introduced Message Driven Beans process messages delivered via the Java Messaging Service. They are stateless, transaction aware components designed to handle asynchronous JMS Messages.

    The use of one way asynchronous calls result in better-perceived performance for distributed applications.

    The solution is that the client instead of looking the ejbHome, is going to look for the JMS topic and start publishing messages and doesn't care about the messages being processed or not. On the server side Message driven beans. Any exceptions thrown or process failure is logged in a logger at the server end.

    Structure:

    The basic architectural layout of both with and without JMS is pictured below. Also the sequence diagram for a sample credit process is specified below.

     
    What are Message Driven Beans:
     Message-Driven Beans

    Message-driven beans are anonymous, stateless, asynchronous message consumers. They are associated at deployment time with a specific JMS message provider (topic or queue), and exclusively the EJB container handles the creation and destruction of MDB instances.
    Application clients cannot actually create or directly call an MDB. Instead, all interaction with an MDB is achieved by sending a JMS message to the topic or queue with which the MDB is registered.

    Because they are not directly visible to the client and they maintain no conversational state, all instances of a particular MDB type are equivalent, which means that the container can easily create a pool of instances to enhance scalability.


    The Sample Code for the Message Driven Session Bean

     public class BankSessionMDB implements MessageDrivenBean, MessageListener {

         private static final boolean VERBOSE = true;

         private MessageDrivenContext messageContext;

         PilotBankSessionHome pilotBankSessionHome = null;

         PilotBankSession pilotBankSession = null;

         public void ejbCreate () throws CreateException {

              openResources();

              log("ejbCreate called");

        }

      

        public void onMessage(Message msg) {

          TextMessage tm = (TextMessage) msg;

          try {

                    String text = tm.getText();

                    this.process(text);

                    tm = null;

          }

          catch(JMSException ex) {

                    ex.printStackTrace();

          }

        }

          public void process(String dataLine) {

            try {

                if(dataLine != null) {

                    StringTokenizer tokenizer = new StringTokenizer(dataLine, "//");

                                    String companyAbbrev = tokenizer.nextToken().trim();

                                    String subsAbbrev = tokenizer.nextToken().trim();

                                    String pilotId = tokenizer.nextToken().trim();

                                    String bankType = tokenizer.nextToken().trim();

                                    String bankBalanceType = tokenizer.nextToken().trim();

                                    String bidPeriodYear = tokenizer.nextToken().trim();

                                    String bidPeriodNumber = tokenizer.nextToken().trim();

                                    String balance = tokenizer.nextToken().trim();

                                    String transType = tokenizer.nextToken().trim();

                                    tokenizer = null;

                                      AbstractBank abstractBank = new AbstractBank((new PilotKey(pilotId, companyAbbrev, subsAbbrev)), Integer.parseInt(bidPeriodNumber), Integer.parseInt(bidPeriodYear), bankType);

                                        if (transType.equals("CREDIT")) {

                                           abstractBank = (AbstractBank) pilotBankSession.creditBank(abstractBank, bankBalanceType, "Trip", Integer.parseInt(balance) , "Initial Load");

                                        }

                                        else if (transType.equals("DEBIT")) {

                                           abstractBank = (AbstractBank) pilotBankSession.debitBank(abstractBank, bankBalanceType, "Trip", Integer.parseInt(balance) , "Initial Load");

                                        }

                                        abstractBank = null;


                     }

                    }

                    catch (java.rmi.RemoteException re) {

                        String logMsg = "RemoteException while Creating PilotBankSession Bean. " + dataLine;

                        System.out.println(logMsg);

                    }

                    catch (fedex.focus.exception.InternalServerException ise) {

                        String logMsg = "InternalServerException while Creating PilotBankSession Bean. " + dataLine;

                        System.out.println(logMsg);

                    }

                    catch (Exception e) {

                        String logMsg = "Exception. " + dataLine;
                        System.out.println(logMsg);

                e.printStackTrace();

                    }

        }

        

     

    Client Code to Publish Messages to the topic reading from file.
    DataInputStream dataInputStream = new DataInputStream(new FileInputStream(fileName));

        while(dataInputStream.available() != 0) {

             dataLine = dataInputStream.readLine().trim();

             fedex.focus.testing.FocusBankPublisher.startJMS();

            fedex.focus.testing.FocusBankPublisher.publishDataString(dataLine);

    Consequences:
    Since its one way communication, we cannot get the result or exception back to the client for each record processing.

    Test Results:

    These are the average values taken from 5 tests.

    With Synchronous File Load

    No of Files : 4

    No of records processed : 34687

    Maximum time taken : 1938 secs (32.3 mins)

      

    With JMS Message Driven Beans

    No of Files : 4

    No of records processed : 34687

    Client finished pushing the data to the topic in 284 secs = 4.73 mins

    (The client is not freed to do the next job. The client need not wait for the server to process all the records submitted for processing)

    Time taken for server processing (834 secs) : 14 mins (Approx)
     

  2. The article reminded me of a similar scenario that I tackled in my previous project.

    On my previous project I tackled the problem of uploading a comma seperated file to a J2EE server. The records were processed via a stateless session bean.

    The architecture proposed in this article has one disadvantage. The architecture sends one record at a time from the client to a J2EE server. So if there are 12,000 records, we're talking about 12000 x 2 trips between the client and the server. That's a lot of network traffic.

    In the architecture that I implemented, all the records were first read by the client, then they were placed in a vector. It was this vector (with 12,000 records) that was eventually sent to the stateless session bean. The session bean processed all the records and finally sent the results back to the client. These results were also encolsed in a vector. Therefore there was only 1 roundtrip between the client and the J2EE server.

    This avoided a lot of network traffic and resulted in a more efficient way of uploading large files.

    Thanks,
    Jamal
  3. Hi,
    The way we are implemented is, since the file size is very large at our end. The client program will do the FTP process to the application server first and then send a simple request to trigger the read process.
    Thou it is going to be individual calls to publish to topic, but still its going to be local for that server. Also the advantage of using message driven beans, depending on the load so many number of message bean instances will be made active to process the data.

    Regards
    Suresh
  4. I agree with you Jamal. A recuring problem occur in the situation where we have a client invoking an EJB synchronously (i.e. a session bean) and we want the EJB to invoke further backend systems in parallel. The solution is to use MDB, ok, but this is not enough when the communication between the client and the EJB container is synchronous. The client (servlet or Java client) shouldn't be aware of the fact that the business logic may be parallelised.

    Alain Hsiung
  5. Hi,

    Your point is well taken and i appreciate the comments made. But i do want to let you know that this approach was taken in the requirement of all the functional sequences from session bean (entry point at server) should remain the same and added to that the client need not have the round trip made even in case of error. All the process needs to do is to log in case of any errors till the whole file process is completed.

    This process can still invoke all the backend systems in parellel. the only difference it has is the server process will be initiated at the server by the message driven bean instance and not by the client's call.
  6. do I understand you correctly? you have the following scenario in the EJB container:
               -----------------------
               | |
               | MDB ------->
               | |
     client----> SB MDB -------> in parallel
               | |
               | MDB ------->
               | |
               -----------------------
    The client calls a SB and MDB are calling other systems in parallel. If this is correct how is the SB returning the total result after the last asynchronous arrived at the MDB?

    Regards
    Alain
  7. Hi Alain,

    The Client programs will read each of their files and publishes records to the JMS inside application server. The MDB's which acts like session bean but only receive asynchrnous calls from the TOPIC will process the records and will log to a file in case of errors.
    If you want the completion notification, you can still send the code in a different format to hte JMS which the MDB instance will figure out to be the completion notification and can log the same.

    the only disadvantage or the compromise that needs to be made is that the client will not receive any notification from the server after the process is completed. the client should follow the put and forget. it has to explicitly read the file for errors.

    You can still create another queue to notify the completion from the server.
  8. Hi Suresh

    The "only disadvantage" you mentioned is exactly what I want to avoid. I want that the client receives the result he asked as the return value of its synchronous call (the result being the total result of all the parallel request on backend systems).

    To achieve this I propose a trick that I called "implicit wait". The facade SB creates an EB and calls a 2nd SB where the EB is passed to SB2. SB2 writes to the EB (but do not commit the changes!) and then send a JMS message to the backend system. Then the calls from SB1 to SB2 returns and SB1 try to write to the EB. This 2nd write produces an implicit wait because a 1st writer (SB2) is not finish (commited). At some time an MDB can receive a JMS response and call the SB2 immediately. This call does a release of the EB. Immediately the EJB container notifies the waiting thread on SB1. Then the SB1 can return the result of the synchronous client call.

    Regards
    Alain
  9. Hi,

    Could the client simply not listen for error on a sperate topic. The Processor (SB or MDB) and easily publish the errors (or successes) to the client asynchornously.

    This allows the client to freely process the file record after record without waiting for the result. This allows the J2EE server to scale to handle several records simultaneously.

    The client can process the error messages on a later pass if required to do so.

                    /------> MDB --> SB --+
    File --> Client/ ------> MDB |
                   \ |
                    \
  10. Hi,
     I have one question.
     If my client is sevelet/jsp, how client came to know
    about either response come or not. if u have any solutions or patterens regarding client is servlet/jsp in asynchronous patteren pleae let me know.
    Thanks
    Venkat
  11. Hi,

      Recently we implemented a server side call back from stateless session EJB (not MDB) using JMS.

      Hence, this pattern can me made more robust if both the client and EJB implement MessageListener and at the end of processing, the MDB can send a notification to the client.

      Even using this enhancement, the client will still be free to carry on with its processing while the MDB processes its results, but it can also keep a track of when the process is completed. Hence, it will be much more generic and applicable to clients which need return data once the processing is complete.

    Regards
    Tyrex