How to keep JSF Conversations from expiring

1.7k Views Asked by At

I have a requirement to keep the JSF 2.2 CDI conversation from expiring. I tried implementing a heartbeat mechanism where I click a 'hidden' button using Ajax which in turn calls a servlet. But the Conversation still expires. I set the timeout to 10s for testing purposes and my code is as shown below.

// The begin conversation method in my managed bean
public void beginConversation() {
      if (conversation.isTransient())
      {
          conversation.setTimeout(10000);
          conversation.begin();
      }
}

// JQuery document ready function
$(document).ready(function() {
setInterval(function(){$.get("/HeartbeatServlet");}, 5000);

});

// Heartbeat servlet
@WebServlet("/HeartbeatServlet")
public class HeartbeatServlet extends HttpServlet{

private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
{
    System.out.println("Heartbeat Received");
    request.getSession();
}
}

It prints the "Heartbeat Recieved" text every 5 seconds. But the conversation still expires.

4

There are 4 best solutions below

2
On

The conversation timeout is how long the conversation will stay alive. It is not a permanent tracker of a conversation. It is not meant to be a keep alive on requests.

There is no extend conversation concept, however you can use begin(id) to recreate a conversation. Any bean state in that conversation will be lost.

1
On

this could be implementation specififc but if you start a conversation with begin() as you do, the framework should append a conversation id as a requestparameter. this is how the conversation is mapped to a request.

with weld as cdi implementation this should be "cid". i dont know how other implementations handle the conversation.

try to append the parameter to your heartbeat request and it should map the conversation and maybe refresh the timeout.

hope that helps

0
On

I've found that keeping a conversation from expiring can be achieved by calling a method on the conversation scoped bean periodically with Primefaces' p:poll, configured to use a reasonable interval (5 min interval has worked for me), no fancy magic required.

2
On

We had the same problem. Adding "cid" to the request for the servlet did not help. In our experience, the heartbeat Servlet does not know about the Conversation. It will keep the current session going, but won't help with the Conversation.

Our solution for this was to add a viewscoped managedbean in which we inject the Conversation. On the UI we used PrimeFaces p:poll to periodically call a method on the managebean.

The method is just printing log statements.

@ManagedBean
@ViewScoped
public class ConversationListener implements Serializable {

...

/**
 * Inject Conversation instance if it is available.
 */
@Inject
private Conversation conversation;
@Inject
FacesBroker facesBroker;

...

/**
 * Method to refresh current conversation
 */
public void renewConversation() {

    if (conversation == null) {
        System.out.println("no conversation");
    } else {
        HttpServletRequest request = (HttpServletRequest) facesBroker.getContext().getExternalContext().getRequest();
        log.info("***     ConversationListener called for conversation ID: {}", new Object[] { conversation.getId() });
        log.info("***     ConversationListener called for session ID: {}", new Object[] { request.getSession().getId() });
    }
}
}