Something really strange with Play framework Global object

45 views
Skip to first unread message

kant kodali

unread,
Mar 24, 2017, 7:11:40 AM3/24/17
to Play Framework
Hi All,

I wrote an app in play that consumes messages from message queue (In our case, we use NSQ (not Kafka) ) and send those messages to group of Web Socket clients that are listening to it. so I want the consumer to be initialized once for each topic and start running forever until the Application itself terminates. What happening is that when I send 10 messages to a topic I can only see 5 messages coming through but when I run the same exact method "startNSQConsumer()" from the code below in a separate Plain old Java application by itself I can see all the 10 messages. So clearly this has something to do with play and I am not sure what is going on. any ideas?

Thanks



public class Global extends GlobalSettings {

private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor();

@Override
public void onStart(Application application) {
EXECUTOR_SERVICE.submit(() -> {
startNSQConsumer();
});
super.onStart(application);
}

@Override
public void onStop(Application application) {
EXECUTOR_SERVICE.shutdown();
super.onStop(application);
}

private void startNSQConsumer() {
NSQLookup lookup = new DefaultNSQLookup();
Configuration config = Play.application().configuration();
List<String> topics = config.getStringList("TOPICS");
String nsqlookupdIP = config.getString("NSQLOOKUPD_IP");
int nsqlookupdPort = Integer.parseInt(config.getString("NSQLOOKUPD_PORT"));
lookup.addLookupAddress(nsqlookupdIP, nsqlookupdPort);
Logger.info("Using nsqlookup at " + nsqlookupdIP + ":" + nsqlookupdPort);
topics.forEach((topic) -> {
NSQConsumer consumer = new NSQConsumer(lookup, topic, topic + "_channel", (message) -> {
String receivedMessage = new String(message.getMessage());
//Logger.info(receivedMessage); // When I enable or disable this I only see 50% of the messages.
EventBusManager.getEventBus().publish(new MsgEnvelope(topic, receivedMessage)); // broadcast message to all Actors listening on a particular topic
message.finished();
}, new NSQConfig(), new NSQErrorCallback() {
@Override
public void error(NSQException x) {
Logger.error("Cause: " + x.getCause() + ", Message: " + x.getMessage());
}
});
consumer.start();
});
}
}

kant kodali

unread,
Mar 24, 2017, 9:36:58 AM3/24/17
to Play Framework
Is it Ok to use Java Executor Service inside Play Framework as I do in the code in this thread? 

Igmar Palsenberg

unread,
Mar 24, 2017, 10:50:49 AM3/24/17
to Play Framework
 
I wrote an app in play that consumes messages from message queue (In our case, we use NSQ (not Kafka) ) and send those messages to group of Web Socket clients that are listening to it. so I want the consumer to be initialized once for each topic and start running forever until the Application itself terminates. What happening is that when I send 10 messages to a topic I can only see 5 messages coming through but when I run the same exact method "startNSQConsumer()" from the code below in a separate Plain old Java application by itself I can see all the 10 messages. So clearly this has something to do with play and I am not sure what is going on. any ideas?

First, as clearly stated in the docs, the Global object is deprecated. It will stop working in the near future. Second, doing these kind of things in the Global scope is a Very Bad Thing (c).
First, see if NSQ has a Apache Camel binding. If yes, start looking at akka-camel. It integrates well with Play, and it makes it a whole lot easier to code it properly.

If that's not available, I suggest putting the whole message handling inside an actor, and have it broadcast events to other actors. It's even worth bribing someone to write a Camel binding for it, or write it yourself : Using actors makes it a whole lot simpler, and you'll spend time on writing functionality, instead of debugging a highly threaded beast.


Igmar

kant kodali

unread,
Mar 24, 2017, 1:17:49 PM3/24/17
to play-fr...@googlegroups.com
Hi Igmar,

Thanks for the reply, I am new to Play framework and Akka as well so I was just trying to see if there is a way where I can call a method only once in the entire application life time. In my case that is startNSQConsumer().I don't see any Camel bindings to NSQ but I like the idea. Also, I wanted to use Actors for modeling this but then again what is that I need to call startNSQConsumer() only once using Actors? For example I don't want it to be called for every WebSocket Connection or request. I can certainly put startNSQConsumer() under PreStart() Method of an Actor but I somehow need to make sure that Actor doesn't get created on every Web socket connection or request which I am not sure how to do it?

Thanks! 

--
You received this message because you are subscribed to a topic in the Google Groups "Play Framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/play-framework/z_O3WgalYp0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to play-framework+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/4580ab5b-80eb-4bba-9054-03e95839241f%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

kant kodali

unread,
Mar 24, 2017, 4:56:54 PM3/24/17
to play-fr...@googlegroups.com
Few people in this post  http://stackoverflow.com/questions/10177626/play-framework-2-0-schedules-an-akka-actor-at-server-launch say to use Global object. But that is also a question 4 years ago. so I am not sure how to start an Actor only once at application startup and perhaps restarts whenever it crashes but definetly not for ever websocket or http request.

Please shine some light
Thanks!

Igmar Palsenberg

unread,
Mar 27, 2017, 2:55:51 AM3/27/17
to Play Framework

 
Thanks for the reply, I am new to Play framework and Akka as well so I was just trying to see if there is a way where I can call a method only once in the entire application life time. In my case that is startNSQConsumer().I don't see any Camel bindings to NSQ but I like the idea. Also, I wanted to use Actors for modeling this but then again what is that I need to call startNSQConsumer() only once using Actors? For example I don't want it to be called for every WebSocket Connection or request. I can certainly put startNSQConsumer() under PreStart() Method of an Actor but I somehow need to make sure that Actor doesn't get created on every Web socket connection or request which I am not sure how to do it?

In general, I stick one-time only actions in a separate class, and bind it in Guice as an eager singleton. That ensures it only runs once. I would personally see if I can find a NSQ binding, since that also makes switching broker at a later stage a lot easier. And you get all the nice Akka / Camel goodies for free.
No idea what kind of work is involved however.

There is a Play websocket chat app floaing around (https://github.com/playframework/play-java-chatroom-example) , that might make a good starting point for the websocket implementation.



Igmar  
Reply all
Reply to author
Forward
0 new messages