about threading
I am trying to make a chat, something similar to what is on facebook.
I need to check if a user received a message from an other one. My first approach was to do a query in ajax every 3 seconds but that's bad so I am changing in order to do a query passing a timestamp. I do an infinite loop where I check the last modification date of the file where I write the conversation of the chat and if the last modification date is greater than the timestamp of the query I then stop the loop and send the result. My problem is that the application becomes completely unresponsive. Any idea what I can do?
Here is the code with the loop:
boolean isNewMessage = false;
List<User> users = new ArrayList<User>();
while(!
String[] files = dir.list();
for(String file:files)
{
String[] tmp = file.split("_");
if(tmp[
File f = new File(file);
if(f.
if(
users.
else
}
}
}
if(!users.
isNewMessage = true;
}
}
Question information
- Language:
- English Edit question
- Status:
- Answered
- Assignee:
- No assignee Edit question
- Last query:
- Last reply:
Revision history for this message
|
#1 |
I'm not sure to understand.
Do you try to stream content over the HTTP response ?
If so, it's currently not possible with play. The framework waits that
the application exits of the controller before to write response
content over the network.
It has a lot of advantages for common cases (response already
committed someone ?) but creating a comet-like request is then
impossible.
On 30 mai 09, at 11:44, marc <email address hidden>
wrote:
> New question #72716 on play framework:
> https:/
>
> I am trying to make a chat, something similar to what is on facebook.
>
> I need to check if a user received a message from an other one. My
> first approach was to do a query in ajax every 3 seconds but that's
> bad so I am changing in order to do a query passing a timestamp. I
> do an infinite loop where I check the last modification date of the
> file where I write the conversation of the chat and if the last
> modification date is greater than the timestamp of the query I then
> stop the loop and send the result. My problem is that the
> application becomes completely unresponsive. Any idea what I can do?
>
> Here is the code with the loop:
> boolean isNewMessage = false;
>
> List<User> users = new ArrayList<User>();
>
> while(!
> String[] files = dir.list();
>
> for(String file:files)
> {
> String[] tmp = file.split("_");
> if(tmp[
> File f = new File(file);
> if(f.lastModifi
> if(tmp[
> users.add((User)
> User.findById(
> else
> users.add((User)
> User.findById(
> }
> }
> }
>
> if(!users.
> isNewMessage = true;
> }
> }
>
> --
> You received this question notification because you are a member of
> play
> framework developers, which is an answer contact for play framework.
Revision history for this message
|
#2 |
I just want to do a request that last as long as the file has not been modified or until the request times out, it's not streaming.
Revision history for this message
|
#3 |
Ok.
play is designed to work with short requests. In fact the default
setting is to work with only one thread (for the controller execution
part at least).
It generally has sense and allows most of the time to achieve best
performance.
If your requests are longs because they are waiting for a busy
resource, you can use more thread. I don't remember anymore exactly
but if you look at the play.Invoker classe you should see some
configuration properties.
Another thing, is that I believe than in Dev mode play will just
serialize requests for easier debugging.
However I think that starting a lot of threads with each ones
executing an infinite loop will just not scale at all. Moreover you
will have to deal with very long database transactions and then a lot
a db concurrency issues.
To do a chat over HTTP you need a comet-like protocol. To allow that
play will need a new artefact (something between a controller and a
job) to allow long HTTP request with non blocking java calls...
It is perhaps the time to start a first implementation.
On 30 mai 09, at 12:32, marc <email address hidden>
wrote:
> Question #72716 on play framework changed:
> https:/
>
> Status: Answered => Open
>
> marc is still having a problem:
> I just want to do a request that last as long as the file has not been
> modified or until the request times out, it's not streaming.
>
> --
> You received this question notification because you are a member of
> play
> framework developers, which is an answer contact for play framework.
Revision history for this message
|
#4 |
I do something like this:
ChatThread thread = new ChatThread(idUser, timestamp);
ExecutorService service = Executors.
Future<List<User>> future = service.
List<User> users;
try {
users = future.get(30, TimeUnit.SECONDS);
} catch (InterruptedExc
Thread.
users = new ArrayList<User>();
} catch (ExecutionException e) {
users = new ArrayList<User>();
} catch (TimeoutException e) {
users = new ArrayList<User>();
}
service.shutdown();
The ChatThread is doing the infinite loop. Creating a thread pool each time is really bad, I'll probably inject it with a spring bean if I find how I could do this in a Controller... I don't have database transactions there.
What I don't really understand is why it seems I can't do more than 1 request at a time? It should be a new HTTP request like if two users were querying the website at same time.
Revision history for this message
|
#5 |
Do you mean that no Controller can be accessed by 2 users at same time?
Revision history for this message
|
#6 |
Not exactly. As the play webserver uses asynchronous NIO il will
accept and read simutanely all HTTP request but will not dedicate any
specific thread for each one. It allows to accept many more
connections than a classic servlet container.
Then it will parse and queue all Request objects. Then a dedicated
thread pool will execute each request.
By default it will uses only 1 thread (or more if you have several
processors). So if a request never responds it will definitevely block
all requests.
You can add more thread to the pool using the play.pool.max property.
But as I said very long requests will not fit with this model.
On 30 mai 09, at 18:05, marc <email address hidden>
wrote:
> Question #72716 on play framework changed:
> https:/
>
> marc gave more information on the question:
> Do you mean that no Controller can be accessed by 2 users at same
> time?
>
> --
> You received this question notification because you are a member of
> play
> framework developers, which is an answer contact for play framework.
Revision history for this message
|
#7 |
And I suspect than in DEV mode it will serialize all requests as it is
easier for debugging.
On 30 mai 09, at 18:05, marc <email address hidden>
wrote:
> Question #72716 on play framework changed:
> https:/
>
> marc gave more information on the question:
> Do you mean that no Controller can be accessed by 2 users at same
> time?
>
> --
> You received this question notification because you are a member of
> play
> framework developers, which is an answer contact for play framework.
Revision history for this message
|
#8 |
Hi,
In play, we wanted simple deployment and performances in production. High networking performances are difficult to achieve with a thread blocking model (IE: One network thread per client). That's why non blocking IO is often used for networking, it allows to have only one thread for many clients "connected". Programming in a non blocking IO environment is quite complicated for users. We wanted to retain high performances and simple thread blocking model for the controller and bellow stuff. Requests are processed with a chain like:
[Network] -> [RequestQueue] -> Executor -> [Network]
The Netowork receives and decodes requests (NIO, 1 thread). They are then queued for processing. The executor is a standard thread pool that pop requests from the queue, executes them and signal netowork the process is complete. If your code does not wait for other IO, we'll use 1 +(1+nb processors) threads. Like Guillaume said, it's not far for the optimal ressource usage for most cases. Your controller code is accessed by more than one thread (executor).
Currently, it's not possible to do what you want to do, but I'm starting to imagine that we could schedule request to issue later replies.
In DEV mode, there is only one thread serving networking and executing your code, ajax and like requests are blocked, I think it's easier for debugging.
Revision history for this message
|
#9 |
Yes jef. I think we should try to reproduce the jetty continuation
support that allow to pause a request, return the thread to the pool,
and then resume it after a timeout.
For your chat marc I think you should try to go back to a polling
mechanism using short lived ajax requests.
Without a good support of comet style request it can't work.
Even using the standard 1 thread per request mode it can't work. A
servlet container has a fixed thread pool too. And if you block them
all for 30 seconds your website will block after 60 users
simulaneously using uour chat.
On 31 mai 09, at 18:30, Jean-Francois POUX <<email address hidden>
> wrote:
> Question #72716 on play framework changed:
> https:/
>
> Jean-Francois POUX proposed the following answer:
> Hi,
>
> In play, we wanted simple deployment and performances in production.
> High networking performances are difficult to achieve with a thread
> blocking model (IE: One network thread per client). That's why non
> blocking IO is often used for networking, it allows to have only one
> thread for many clients "connected". Programming in a non blocking
> IO environment is quite complicated for users. We wanted to retain
> high performances and simple thread blocking model for the
> controller and bellow stuff. Requests are processed with a chain like:
> [Network] -> [RequestQueue] -> Executor -> [Network]
>
> The Netowork receives and decodes requests (NIO, 1 thread). They are
> then queued for processing. The executor is a standard thread pool
> that
> pop requests from the queue, executes them and signal netowork the
> process is complete. If your code does not wait for other IO, we'll
> use
> 1 +(1+nb processors) threads. Like Guillaume said, it's not far for
> the
> optimal ressource usage for most cases. Your controller code is
> accessed
> by more than one thread (executor).
>
> Currently, it's not possible to do what you want to do, but I'm
> starting
> to imagine that we could schedule request to issue later replies.
>
> In DEV mode, there is only one thread serving networking and executing
> your code, ajax and like requests are blocked, I think it's easier for
> debugging.
>
> --
> You received this question notification because you are a member of
> play
> framework developers, which is an answer contact for play framework.
Revision history for this message
|
#10 |
Well,
We have introduced a new feature in the latest revision to allow very long blocking HTTP requests with non-blocking Java execution.
You can now call request.
Basically you can rewrite your code like this :
public static void checkNewMessages() {
boolean newMessages = ...;
if(newMessage) {
}
request.
}
The checkNewMessages() action will be called every 2 seconds until a new message is found. This will block the HTTP response until the action return something. But it will not block any thread. If the client close the HTTP connection the suspended invocation will be discarded.
I'm sure it will miss some features as is just a first try, but if you could try it on your real use case, it would help us a lot.
Thank you !
Revision history for this message
|
#11 |
This sounds like a pretty good solution, however is there anyway that one could pass a thread to request.suspend. Basically creating something similar to a twisted defer to thread. So instead of just calling request.
Hope this came out better than i think it did, in anycase i will look into the play source code and see if i cant figure out how to do this and maybe send though a solution?
Revision history for this message
|
#12 |
Yes, I've already thought to have a waitFor() method that wait for a
Future task completion. The jobs API need to be completed, but the
idea is to achieve something like :
Future reportGenerated = new GenerateReportJ
waitFor(
Not sure how this could be implemented however ... You're welcome to take a try.
On Wed, Jun 17, 2009 at 12:21 AM,
lmatshoba<email address hidden> wrote:
> Question #72716 on play framework changed:
> https:/
>
> lmatshoba requested for more information:
> This sounds like a pretty good solution, however is there anyway that
> one could pass a thread to request.suspend. Basically creating
> something similar to a twisted defer to thread. So instead of just
> calling request.
> request.
> framework once complete and as such allow the request to return with
> whatever data it was processing?
>
> Hope this came out better than i think it did, in anycase i will look
> into the play source code and see if i cant figure out how to do this
> and maybe send though a solution?
>
> --
> You received this question notification because you are a member of play
> framework developers, which is an answer contact for play framework.
>
Revision history for this message
|
#13 |
Downloaded the latest sources last night and checked all the changes that where made inorder to get the suspend function going. I think it might actually not be too hard to do, just trying to make sure I think of use cases outside my own one to see if I can cover those aswell, dont want to make it too narrow.
What i am thinking is that it might be best to define our own class similar to a future that can be pushed onto a queue once it has completed execution. This will make it easier in that you wont have to poll it. There can actually be a pool of these threads. But this might not be the best way, I will have a closer look at how Twisted does this sort of thing and maybe steal some logic from there.
I will try work on something in the next couple of days, wish me luck.
Can you help with this problem?
Provide an answer of your own, or ask marc for more information if necessary.