Daniel
http://www.theserverside.com/news/thread.tss?thread_id=45164
http://weblogs.java.net/blog/jfarcand/archive/2007/05/first_community.html
# Grizzly Comet: A tiny/embeddable web server which support Comet
Request Processing
# Grizzly Cometd: A tiny/embeddable web server which support Cometd/
Bayeux JSON based protocol.
http://weblogs.java.net/blog/jfarcand/archive/2007/04/new_bayeux_spec.html#comments
Well, there you go. Those are the resources that I have found. Hope
that helps,
Cameron
On May 12, 7:52 am, dflorey <daniel.flo...@gmail.com> wrote:
1. Jetty has continuations. Unless you want your server to come to a
grinding halt on pathetically small loads, you NEED continuations.
Continuations scale. Tomcat does not scale for server push.
2. Jetty has support for cometd, but cometd is a protocol to multiplex
unrelated 'server push' connections across a single connection. The
reason you need to do that, is because browsers only open at most 2
connections to a single host. Usually you don't have multiple
unrelated streams that all need server push. In those circumstances,
cometd is pure overkill, and you shouldn't use it.
3. server push has a metric kilopissload (about 4 imperial buttloads)
of caveats, quid pro quos, and other nasty surprises. You really need
to know what you're doing. to wit:
- IE can't handle reading server push properly (There are hacks, but
those don't work on other browsers), so you need to implement half
server push: dangle the connection, yes, but close it right after
sending a single 'packet' of information. E.g., a single chat line.
- proxies don't know about server push. Again, closing the connection
can help 'flush the stream' as it were, but even with that (also
solves IE problem above), proxies tend to just call timeout and close
the connection after a while of no traffic. This means you should
probably be sending inconsequential characters (usually whitespace)
every so often, and close down the connection after a minute or two
with the notification to the client that A. nothing happend and B. if
the client would be so kind to re-open the same connection?
and I haven't even covered the half of it.
Did you guys read this more extensive comment?
On May 12, 9:14 pm, "charlie.coll...@gmail.com"
<charlie.coll...@gmail.com> wrote:
> Might want to check out Luca Masini's work with Comet and GWT:http://www.jroller.com/page/masini?entry=a_comet_implementation_for_g....
> http://groups.google.com/group/Google-Web-Toolkit/browse_thread/threa...
>
> On May 12, 9:14 pm, "charlie.coll...@gmail.com"
>
>
>
> <charlie.coll...@gmail.com> wrote:
> > Might want to check out Luca Masini's work with Comet and GWT:http://www.jroller.com/page/masini?entry=a_comet_implementation_for_g....
>
> > On May 12, 7:52 am, dflorey <daniel.flo...@gmail.com> wrote:
>
> > > Hi,
> > > I just started to implement my first GWT-based app and I came across
> > > the requirement that I need a listener on client side that gets
> > > actively notified by server event. A pull-approach is not feasable as
> > > I need realtime-notifications.
> > > I finally implemented a notification mechanism based on "hanging"
> > > listener threads for each client. I know that this has many
> > > disadvantages (tomcat needs to provide enough listener threads to
> > > server all clients) but I wonder if anybody is interested in this.
> > > I could provide a reusable & simplified version if appreciated but
> > > perhaps I'm completely on the wrong track and there might be a better
> > > solution availbale already?
>
> > > Daniel- Zitierten Text ausblenden -
>
> - Zitierten Text anzeigen -
Cheers,
Daniel
> > - Zitierten Text anzeigen -- Zitierten Text ausblenden -
You then make a request for 'all events with id 858 and up'. There are
now 2 scenarios:
1. event with id 858 already happend. In this case, send ALL events
numberred 858 and up to the client, then close the connection; no
server push aspect at all in this scenario. e.g: if id 861 is already
on the books, send 858, 859, 860, and 861, then close the connection.
2. event with id 858 hasn't actually happend yet. throw the
RetryException (jetty's continuation system) or freeze the thread
(tomcat unscalable server push) and wait for 858 to happen. Wake up
every 20 seconds and push a noop across the line (e.g. whitespace).
Once 858 happends, send it and close the connection. If 858 never
happends, after 90 seconds or so, send an explicit no-data marker and
close the connection.
As a client you know where you are, event-wise. Let's say you've got 1
through 857 covered, so you make a request for 858. Three things can
now happen:
1. You get a bunch of events in, (how long it took isn't important;
the fact that the server might be in scenario #1 or #2 is not relevant
client side). You do what you're supposed to do with them (in a chat
app, for example, display the lines in the browser), update your
internal state counter as 'I've processed up to e.g. 861', and
immediatly re-open the connection, this time asking for 862 and
upwards. clear the error counter.
2. You get no events in, but you do get the specific no-data marker.
You re-open the connection for the same event id (858, again). clear
the error counter.
3. You get no events in, and no specific no-data marker. Sounds like
server trouble. Increase the error counter. If the error counter is at
5, stop the app and update the browser to reflect there's some sort of
network problem. The reason you need this scenario is because without
it, your app might faulty endlessly retry the connection, faultily
concluding the server simply has no data for us and would like for us
to re-connect, completely freezing out the browser as you try and fail
the AJAX call thousands of times a second. You might consider trying
to reconnect every 30 seconds or so, so that your app can jump right
back in the moment networking is restored, or the moment the server
recovers (as you can't really know if the server just went down, or
the local user's network, or something in between, unless you do some
heuristics on exactly how long it takes for the connection to fail.
Not recommended - quick return doesn't neccessarily mean it's a local
problem, and significant time passed between attempt and failure does
not neccessarily mean there is no local problem).
Daniel
package com.floreysoft.cti.server;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.floreysoft.cti.client.Event;
import com.floreysoft.cti.client.MessageEvent;
public class EventQueue {
private static final long TIMEOUT = 60000;
private static final int MAX_EVENTS = 10;
public static EventQueue eventQueue = new EventQueue();
private Map<String, List<Event>> eventMap = new HashMap<String,
List<Event>>();
private Map timestamps = new HashMap();
private boolean showMissedEvents = false;
private int maxEvents = MAX_EVENTS;
private long timeout = TIMEOUT;
public static EventQueue getInstance() {
return eventQueue;
}
public void addEvent(String sessionHandle, Event event) {
List<Event> eventList;
synchronized (eventMap) {
eventList = eventMap.get(sessionHandle);
if (eventList == null) {
eventList = new ArrayList<Event>();
eventMap.put(sessionHandle, eventList);
}
}
synchronized (eventList) {
eventList.add(event);
if (eventList.size() > maxEvents) {
eventList.remove(0);
}
eventList.notify();
}
}
public List<Event> getEvents(String sessionHandle) {
List<Event> eventList = getEventList(sessionHandle);
synchronized (eventList) {
try {
eventList.wait(timeout);
} catch (InterruptedException e) {
// Ignore
}
}
return eventList;
}
private List<Event> getEventList(String session) {
List<Event> eventList;
synchronized (eventMap) {
eventList = eventMap.get(session);
if (eventList == null) {
eventList = new ArrayList<Event>();
eventMap.put(session, eventList);
}
}
return eventList;
}
@SuppressWarnings("unchecked")
public List getNewEvents(String session) {
Date lastTimestamp = (Date) timestamps.get(session);
List<Event> eventList = null;
List newEvents = new ArrayList();
if (lastTimestamp == null) {
if (showMissedEvents) {
lastTimestamp = new Date(0);
eventList = getEventList(session);
} else {
lastTimestamp = new Date();
// Wait for next event
eventList = getEvents(session);
}
timestamps.put(session, lastTimestamp);
} else {
// Check for events that might have been occured in the meantime
eventList = getEventList(session);
synchronized (eventList) {
for (Event event : eventList) {
if (event.getTimestamp().after(lastTimestamp)) {
newEvents.add(event);
}
}
if (newEvents.size() > 0) {
timestamps.put(session, new Date());
return newEvents;
} else {
// No events in the meantime, so wait for new events
eventList = getEvents(session);
timestamps.put(session, new Date());
}
}
}
synchronized (eventList) {
for (Iterator i = eventList.iterator(); i.hasNext();) {
Event event = (Event) i.next();
if (event.getTimestamp().after(lastTimestamp)) {
newEvents.add(event);
}
}
}
return newEvents;
}
}
On 13 Mai, 18:31, Reinier Zwitserloot <reini...@gmail.com> wrote:
On May 14, 9:43 am, dflorey <daniel.flo...@gmail.com> wrote:
> This is how my server code looks like:
>
> [snip]
Hi Reinier,
I was just following up on this topic, I'm new to Jetty Continuations so if you have some time could you elaborate on what actually needs to be done to transform it to the Jetty Cont. philosophy.
Another question, I'm designing a fully GWT enabled application, so the full app is contained in one single .html, I have a lot of small client / server requests, will it drastically improve performance when changing to continuations? What is your vision on this?
Grtz
Continuations help ONLY for when you ordinarily would freeze the
thread waiting for an external event (so not a db return or file
access, something that would be trigger by another request and might
take multiple seconds).
The only practical way to improve performance when you have lots of
small requests is to turn them into larger requests. Instead of making
3 sequential calls, make 1 servlet that makes those 3 calls for you
and rolls them into a single GWT-RPC return object / JSON return
value / XML stream - whatever protocol you're using. That'll help. Not
much, but a little.
On May 15, 9:59 am, "Maarten Volders" <maarten.vold...@gmail.com>
wrote:
> Hi Reinier,
>
> I was just following up on this topic, I'm new to Jetty Continuations so if
> you have some time could you elaborate on what actually needs to be done to
> transform it to the Jetty Cont. philosophy.
> Another question, I'm designing a fully GWT enabled application, so the full
> app is contained in one single .html, I have a lot of small client / server
> requests, will it drastically improve performance when changing to
> continuations? What is your vision on this?
>
> Grtz
>
> On 5/15/07, Maarten Volders <maar...@sherpa-consulting.be> wrote:
>
>
>
> > Hi Reinier,
>
> > I was just following up on this topic, I'm new to Jetty Continuations so
> > if you have some time could you elaborate on what actually needs to be done
> > to transform it to the Jetty Cont. philosophy.
> > Another question, I'm designing a fully GWT enabled application, so the
> > full app is contained in one single .html, I have a lot of small client /
> > server requests, will it drastically improve performance when changing to
> > continuations? What is your vision on this?
>
> > Grtz
>