This isn't a JSF problem, it's a fundamental HTTP problem.
HTTP is not designed to be a client/server session-based protocol. It's a quick-response one-off protocol that simulates sessions by the use of various tricks. Effectively, each time you hit submit, you connect, get a response and disconnect and it's only thanks to those tricks that the next request can be related to the previous request.
Because HTTP
is designed as a quick-response protocol,
you should not attempt to execute long-running processes in HTTP request-processing code. You not only will time out browsers, you will hog critical server resources. Nor should you attempt to spawn threads off the request-processing code, because the request threads are pooled and may not (per the
J2EE spec) spawn child threads.
To handle this common problem, you need to set up an independent processor outside of the HTTP request/response processors and let it manage long-running tasks. The HTTP processors then become responsible to entering requests to the backend engine and monitoring and controlling the backend engine.
A popular way of doing this is to spawn a
thread from a ServletContextListener when the webapp starts up. Unlike HTTP processors, the ServletContextListener thread is permitted to do this. That thread can then run the engine, which typically maintains a request processing queue that HTTP request processors add backend processing requests to. The engine then pulls requests from the queue and hands them off the the code that actually does the long-running process.
As I said, this is a very common problem. In fact, I have to do one of them this week!