Search code examples
jsfsingletonload-balancingjavabeansserver-side

Does load balancing in the server side of a web app generate multiple instances of a singleton AppScoped bean of JSF?


Suppose I deploy my web app on AWS or GAE and my app in JSF has a Singleton ApplicationScoped Bean with methods "void setList( List)" "List getList()". I call this methods from a SessionScoped bean when a user makes modifications to the list. I want to ensure that all users get the changes in their own session by pushing a notification message to them so that they can get the list again. If the load balancer of AWS or GAE splits the app in several instances, how do they manage this singleton ApplicationScoped bean? Are there many instances of the singleton? how are they synchronized? is there any risk that one instance has different information?

I suppose all instances of the app in each server participating in the load balancing needs to be updated somehow but this would kill the purpose of load balancing since the work would be replicated everywhere. It might be possible that the singleton work is not load balanced but I don't know. The documentation is very extense and hard to get familiar with.

@ManagedBean( name = "theModelBean",
              eager = true )
@Singleton
@ApplicationScoped

public class ModelBean {
  ArrayList<Data> theList;

  public List<Data> getList(){
    return theList;
  }

  public void setList( List<Data> aList ) {
    this.theList = aList;
  }
}


@ManagedBean( name = "theController" )
@SessionScoped

public class Controller {

  @ManagedProperty(value = "#{theModelBean}")
  private ModelBean theModelBean;

  public foo(){
    ArrayList<Data> list = new ArrayList<>;
    list.add( new Data() );
    theModelBean.setList( list );
  }
}

I wish load balancing does not interfere with my logic and that it handles everything in a transparent way for me. Otherwise I might have to make theModelBean write the list to the database everytime it changes and get it from there everytime it is requested from a session.


Solution

  • I'll ignore the "load balancing" / "load balanced" terms in your question and assume that you actually meant "clustering" / "clustered". As in: the same WAR file is being deployed to multiple servers which are all behind a single proxy (who does the actual load balancing, but load balancing itself is not the cause of the observed problem).

    Yes, each server of the cluster will get its own instance of any "application scoped" bean. This not only includes the JSF @javax.faces.bean.ApplicationScoped, but also the CDI @javax.enterprice.context.ApplicationScoped and @javax.inject.Singleton and the EJB @javax.ejb.Singleton.

    The normal approach is indeed to keep track of shared data in a single common data source which is used by all servers of the cluster. Usually a SQL-based RDBMS is being used for that. Usually you fire a SQL query to obtain the most recent data from the DB on every request/view. If you're using JPA for that, you usually use 2nd level cache to cache the data so that the amount of DB hits will be reduced. This can be configured cluster-wide.

    If the data is immutable (i.e. read-only after creation), then the alternative approach to saving in a DB is to rely on session persistence. Have a @SessionScoped bean which reads from the @ApplicationScoped one during writeObject() and writes-if-absent to the @ApplicationScoped during readObject(). One real world example is implemented in the code behind the JSF <f:websocket> and OmniFaces <o:socket>.