user3757849
user3757849

Reputation: 239

Java EE AsyncContext Per Client

I'm using asynchronous servlets for a long running process and have implemented long polling on the client side so it can display progress and notify the client when complete. I have a notifier servlet implemented that manually sorts out which clients get what message by manually inserting a session id via an custom EventNotify class. If the getEventId() is not the same as eventid, we send "IGNORE" to the client and the client manually ignores the message. notifyPeers automatically sends out the notification to ALL clients. If a lot of long running jobs are running, this can become really noisy. Is there a way to have notifyPeers only send out notification to just the client that the AsyncContext is registered with? Thanks in advance!

@Singleton
public class Notifier {
    private final Queue<AsyncContext> peers = new ConcurrentLinkedQueue();
    private final HashMap<AsyncContext, String> acsessionmap = new HashMap<AsyncContext, String>();

    public void notifyPeers(@Observes EventNotify evn) {
        for (AsyncContext ac : peers) {
            try {
                String aceventid = acsessionmap.get(ac);
                final ServletOutputStream os = ac.getResponse().getOutputStream();
                if (Util.equals(aceventid, evn.getSessd())) {
                    os.println(evn.getSessid() + ": " + evn.getMessage());
                } else {
                    os.println("IGNORE");
                }
                ac.complete();
            } catch (IOException ex) {
            } finally {
                peers.remove(ac);
            }
        }
    }

public void addAsyncContext(final AsyncContext ac, String sessid) 
    ...
    acsessionmap.put(ac,sessid);
    peers.add(ac);

Upvotes: 2

Views: 92

Answers (1)

user3757849
user3757849

Reputation: 239

Here is a solution. Getting rid of @Singleton does not work because the AsyncContexts stopped "connecting" at all.
What does work is keeping the singleton and getting rid of the Queue peers. Instead, maintain a hashmap:

private final HashMap<String, AsyncContext> sessionacmap = new HashMap<String, AsyncContext>();

sessionacmap.put(sessid, ac);

instead of the peers loop:

    for (AsyncContext ac : peers) {

Pull only the asynccontext and act upon that:

    AsyncContext ac = sessionacmap.get(evn.getEventid());
    if (ac==null) return;
    try {
        final ServletOutputStream os = ac.getResponse().getOutputStream();
    ....

The result is only the client requesting a particular job will be notified upon the events related to that job only. Not noisy at all and should scale well. Websockets should work too, but we have a load balancer issue with websockets in our particular case.

Upvotes: 1

Related Questions