akka novice here. Currently building a system to call some web services and update database... but akka actors are not working exactly as expected...My code sample...
Application Runner
public class Application
{
public static void main(String[] args) throws InterruptedException
{
ActorSystem system = ActorSystem.create("system");
ActorRef master = system.actorOf(Props.create(MasterActor.class));
String url = "http://some-web-service-url";
master.tell(url, ActorRef.noSender());
system.shutdown();
}
}
MasterActor
public class MasterActor extends UntypedActor
{
private final LoggingAdapter log = Logging.getLogger(getContext().system(), getSelf());
private final ActorRef childActor = getContext().actorOf(Props.create(ChildActor.class));
#Override
public void onReceive(Object message) throws Exception
{
if(message instanceof String)
{
childActor.tell(message, getSelf());
}else if(message instanceof Boolean){
log.info("all done");
}else {
unhandled(message);
}
}
}
ChildActor
public class ChildActor extends UntypedActor
{
private final LoggingAdapter log = Logging.getLogger(getContext().system(), getSelf());
#Override
public void onReceive(Object message) throws Exception
{
if (message instanceof String) {
String url = (String) message;
Integer result = getWebServiceResult(url);
log.info("result: {}", result);
getSender().tell(true, getSelf());
}else {
unhandled(message);
}
}
private Integer getWebServiceResult(final String url) throws Exception
{
ExecutionContextExecutor executor = getContext().dispatcher();
Future<Integer> future = Futures.future(new Callable<Integer>()
{
#Override
public Integer call() throws Exception
{
return new HttpClient().fetchData(url); //some web service call
}
}, executor);
return (Integer) Await.result(future, Duration.create(7000, TimeUnit.SECONDS));
}
}
but child actor is unable to send the message to its sender, master...getting this error stack...
[INFO] [03/28/2015 01:02:45.521] [system-akka.actor.default-dispatcher-3] [akka://system/user/$a/$a] result: TheWebservice Result
[INFO] [03/28/2015 01:02:45.528] [system-akka.actor.default-dispatcher-4] [akka://system/user/$a] Message [java.lang.Boolean] from Actor[akka://system/user/$a/$a#1601481298] to Actor[akka://system/user/$a#1257171720] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
I am unable to find what's wrong (spent 3 days)... In my sense this code should work...can you tell me what's I am doing wrong.
Thanks in advance...
You have a race condition. You're shutting down your ActorSystem
system.shutdown();
before the child actor has a chance to send its reply. Remember that more or less everything in akka is asynchronous.
Add, for example, a
Thread.sleep(someTime);
before the shutdown to see the message sent and received.
Just to deal with the exit part :
You could register a shutdown hook like below and shutdown the akka system in it
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
system.shutdown();
}
});
Then enter into a never ending loop as shown below while waiting for the processing to complete so that when it is done processing you press Ctrl + C on your terminal or raise a System.exit(0) within your code.
while(false == shutdownFlag){
Thread.sleep(sometime);
}
Related
I'm building my first telegram bot. It send one message every 5 seconds to the user.
While it sends it to one user it cannot receive update from other chat.
public void foo(msg, Update update){
msg.setChatId(update.getMessage().getChatId());
for (int i = 1; i < links.size(); i++){
msg.setText(links.get(i));
execute(msg);
}
Thread.sleep(wait * 1000);
}
How can I use Thread? I've tried creating multiple thread here
public static void bot(){
ApiContextInitializer.init();
TelegramBotsApi telegramBotsApi = new TelegramBotsApi();
try {
telegramBotsApi.registerBot(new myBot());
} catch (TelegramApiException e) {
e.printStackTrace();
}
But he tries to create multiple bots and fails. Same if this is the runnable function:
How can I do it? I'm Stuck. I cannot create this function in different thread
public void onUpdateReceived(Update update) {
leggi(new SendMessage(), update.getMessage().getText(), update);
//.setChatId(update.getMessage().getChatId())
public void leggi(SendMessage msg, String command, Update update){
if(command.equals("test") {
foo( msg, update);
}
Here the full code... https://github.com/siamoInPochi/Ilsottomarinobot/tree/prova/src/main/java/Ilsottomarinobot
If you spawn a thread for every bot user who wants to receive messages, you will quickly be out of computer's resources in case of high number of users. So I think threads is not a good idea for your task.
In my mind more natural approach is the following:
Find a library with an HTTP server.
Switch from GetUpdates to webhooks.
Schedule send-message-to-user-every-5-seconds tasks to server's event loop.
Send messages every 5 seconds asynchronously.
You can make it with this library https://github.com/pengrad/java-telegram-bot-api
<dependency>
<groupId>com.github.pengrad</groupId>
<artifactId>java-telegram-bot-api</artifactId>
<version>4.2.0</version>
</dependency>
Subscribe to new updates via bot.setUpdatesListener
Send messages via bot.execute(new SendMessage(chatId, link), callback)
Full working example:
static String[] links = {"1", "2", "3"};
static Callback emptyCallback = new Callback() {
#Override
public void onResponse(BaseRequest request, BaseResponse response) {
}
#Override
public void onFailure(BaseRequest request, IOException e) {
e.printStackTrace();
}
};
static void foo(TelegramBot bot, Update update) {
Message message = update.message();
if (message == null) return;
Long chatId = message.chat().id();
for (String link : links) {
bot.execute(new SendMessage(chatId, link), emptyCallback);
}
}
public static void main(String[] args) {
TelegramBot bot = new TelegramBot(TOKEN);
bot.setUpdatesListener(updates -> {
for (Update update : updates) {
foo(bot, update);
}
return UpdatesListener.CONFIRMED_UPDATES_ALL;
});
}
I'm currently trying to achieve a somewhat stable connection between a micro-controller and a Java-application using netty 4.0.44.Final and rxtx. From time to time the controller asks for a time-stamp, otherwise it is just forwarding sensor data to my application. The application is able to receive as many packages as I want to until i call writeAndFlush() somewhere in the pipeline (i.e. answering a time-request). The pipeline correctly writes data on the outputstream (when writeAndFlush() is called) and from that point onwards my application is never receiving data again and I have no idea why.
public class WsnViaRxtxConnector extends AbstractWsnConnector{
private static final Logger LOG = LoggerFactory.getLogger(WsnViaRxtxConnector.class);
private String port;
private Provider<MessageDeserializer> deserializerProvider;
private ChannelFuture channelFuture;
public ChannelKeeper keeper;
#Inject
public WsnViaRxtxConnector(Provider<MessageDeserializer> deserializerProvider, ChannelKeeper keeper) {
this.deserializerProvider = deserializerProvider;
this.port = Configuration.getConfig().getString("rest.wsn.port");
this.keeper = keeper;
System.setProperty("gnu.io.rxtx.SerialPorts", this.port);
}
#Override
protected void run() throws Exception
{
EventLoopGroup group = new OioEventLoopGroup();
//final EventExecutorGroup group2 = new DefaultEventExecutorGroup(1500);
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(RxtxChannel.class)
.handler(new ChannelInitializer<RxtxChannel>() {
#Override
public void initChannel(RxtxChannel ch) throws Exception {
ch.pipeline().addLast(new DleStxEtxFrameDecoder(), new DleStxEtxFrameEncoder());
ch.pipeline().addLast(new IntegrityCheck(),new IntegrityCalculation());
ch.pipeline().addLast(new AesCcmDecrypter(),new AesCcmEncrypter());
ch.pipeline().addLast(deserializerProvider.get(),new MessageSerializer());
ch.pipeline().addLast(new TimeStampJockel());
}
})
.option(RxtxChannelOption.BAUD_RATE, 19200);
ChannelFuture f = b.connect(new RxtxDeviceAddress(this.port)).sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
The handlers are all pretty much standard implementations and seem to work when receiving packages only. The pipeline should first generate an object from the raw data, checkCRC, decrypt, deserialize and then compute some logic (aka generate a time-response).
public class TimeStampJockel extends ChannelInboundHandlerAdapter{
private static final Logger LOG = LoggerFactory.getLogger(TimeStampJockel.class);
private EventBus bus;
private ChannelKeeper keeper;
#Inject
public TimeStampJockel(){
this.bus = GlobalEventBus.getInstance();
this.keeper = keeper;
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg){
LOG.debug("Creating packet from received data");
RawPacket raw = (RawPacket)msg;
//EventExecutor ex = ctx.executor();
//LOG.debug("inexecutor.EventLoop(1):" + ex.inEventLoop());
//keeper.addChannelHandlerContext(raw.getSource(),ctx);
ByteBuf buf = raw.getContent();
LOG.debug("\tBuffer: {}", HelperFunctions.getBufferAsHexString(buf));
UnsignedLong mac = UnsignedLong.fromLongBits(21);
while(buf.readerIndex()<buf.writerIndex())
{
int type = buf.readShort();
int length = buf.readShort();
ByteBuf value = buf.readBytes(length);
if(PacketType.getEnum(type).equals(PacketType.MAC))
{
mac = UnsignedLong.valueOf(value.readLong());
}
else
{
AbstractPacket packet = PacketFactory.createPacket(PacketType.getEnum(type), raw.getVersion(), raw.getPacketType(), raw.getSource(), raw.getSource(), raw.getDestination(), mac, value);
if(packet instanceof TimeReqPacket) {
TimeReqPacket timeReqPacket = (TimeReqPacket) packet;
Duration d = HelperFunctions.timeSinceYear2000();
TimeRespPacket newPacket = new TimeRespPacket(Constants.PROTOCOL_VERSION, PacketType.TIME_RESP.getValue(), packet.getGatewayAdr(),UnsignedLong.valueOf(Configuration.getConfig().getLong("rest.wsn.mac", Long.MAX_VALUE)),timeReqPacket.getMac(),timeReqPacket.getMac(),d.getStandardSeconds(),HelperFunctions.getMillisOfDuration(d));
ctx.write(newPacket);
} else {
bus.post(packet);
}
}
}
}
The received sensor data is pushed to a Guava-bus (unless its a time-request) and processed by other components. If the incoming package is a time-request-packet, the previously displayed component should generate a time-stamp-packet and writeAndFlush() is down the pipeline. Any ideas what may cause that issue? I'm pretty much out of ideas - I have been googling the last 10 hours without meaningful results and I have no unchecked resources left. I'm using ubuntu 16.04, thanks in advance.
[EDIT] I tried checking the ChannelFuture, by adding the following code-snippet to the last pipeline handler
ChannelFuture f = ctx.writeAndFlush(newPacket);
f.addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
LOG.error("Server failed to send message", future.cause());
future.channel().close();
}
}
[EDIT2] Found my error. It was a netty version conflict. I am working with multiple versions of netty in different projects and was using an older netty version (4.0.13) instead of netty 4.044.final. I have no idea what changed between those versions but I am glad that everything is working properly now.
Play 2.5 Highlights states
Better control over WebSocket frames
The Play 2.5 WebSocket API gives you direct control over WebSocket frames. You can now send and receive binary, text, ping, pong and close frames. If you don’t want to worry about this level of detail, Play will still automatically convert your JSON or XML data into the right kind of frame.
However
https://www.playframework.com/documentation/2.5.x/JavaWebSockets has examples around LegacyWebSocket which is deprecated
What is the recommended API/pattern for Java WebSockets? Is using
LegacyWebSocket the only option for java websockets?
Are there any examples using new Message types ping/pong to implement a heartbeat?
The official documentation on this is disappointingly very sparse. Perhaps in Play 2.6 we'll see an update to this. However, I will provide an example below on how to configure a chat websocket in Play 2.5, just to help out those in need.
Setup
AController.java
#Inject
private Materializer materializer;
private ActorRef chatSocketRouter;
#Inject
public AController(#Named("chatSocketRouter") ActorRef chatInjectedActor) {
this.chatSocketRouter = chatInjectedActor;
}
// Make a chat websocket for a user
public WebSocket chatSocket() {
return WebSocket.Json.acceptOrResult(request -> {
String authToken = getAuthToken();
// Checking of token
if (authToken == null) {
return forbiddenResult("No [authToken] supplied.");
}
// Could we find the token in the database?
final AuthToken token = AuthToken.findByToken(authToken);
if (token == null) {
return forbiddenResult("Could not find [authToken] in DB. Login again.");
}
User user = token.getUser();
if (user == null) {
return forbiddenResult("You are not logged in to view this stream.");
}
Long userId = user.getId();
// Create a function to be run when we initialise a flow.
// A flow basically links actors together.
AbstractFunction1<ActorRef, Props> getWebSocketActor = new AbstractFunction1<ActorRef, Props>() {
#Override
public Props apply(ActorRef connectionProperties) {
// We use the ActorRef provided in the param above to make some properties.
// An ActorRef is a fancy word for thread reference.
// The WebSocketActor manages the web socket connection for one user.
// WebSocketActor.props() means "make one thread (from the WebSocketActor) and return the properties on how to reference it".
// The resulting Props basically state how to construct that thread.
Props properties = ChatSocketActor.props(connectionProperties, chatSocketRouter, userId);
// We can have many connections per user. So we need many ActorRefs (threads) per user. As you can see from the code below, we do exactly that. We have an object called
// chatSocketRouter which holds a Map of userIds -> connectionsThreads and we "tell"
// it a lightweight object (UserMessage) that is made up of this connecting user's ID and the connection.
// As stated above, Props are basically a way of describing an Actor, or dumbed-down, a thread.
// In this line, we are using the Props above to
// reference the ActorRef we've just created above
ActorRef anotherUserDevice = actorSystem.actorOf(properties);
// Create a lightweight object...
UserMessage routeThisUser = new UserMessage(userId, anotherUserDevice);
// ... to tell the thread that has our Map that we have a new connection
// from a user.
chatSocketRouter.tell(routeThisUser, ActorRef.noSender());
// We return the properties to the thread that will be managing this user's connection
return properties;
}
};
final Flow<JsonNode, JsonNode, ?> jsonNodeFlow =
ActorFlow.<JsonNode, JsonNode>actorRef(getWebSocketActor,
100,
OverflowStrategy.dropTail(),
actorSystem,
materializer).asJava();
final F.Either<Result, Flow<JsonNode, JsonNode, ?>> right = F.Either.Right(jsonNodeFlow);
return CompletableFuture.completedFuture(right);
});
}
// Return this whenever we want to reject a
// user from connecting to a websocket
private CompletionStage<F.Either<Result, Flow<JsonNode, JsonNode, ?>>> forbiddenResult(String msg) {
final Result forbidden = Results.forbidden(msg);
final F.Either<Result, Flow<JsonNode, JsonNode, ?>> left = F.Either.Left(forbidden);
return CompletableFuture.completedFuture(left);
}
ChatSocketActor.java
public class ChatSocketActor extends UntypedActor {
private final ActorRef out;
private final Long userId;
private ActorRef chatSocketRouter;
public ChatSocketActor(ActorRef out, ActorRef chatSocketRouter, Long userId) {
this.out = out;
this.userId = userId;
this.chatSocketRouter = chatSocketRouter;
}
public static Props props(ActorRef out, ActorRef chatSocketRouter, Long userId) {
return Props.create(ChatSocketActor.class, out, chatSocketRouter, userId);
}
// Add methods here handling each chat connection...
}
ChatSocketRouter.java
public class ChatSocketRouter extends UntypedActor {
public ChatSocketRouter() {}
// Stores userIds to websockets
private final HashMap<Long, List<ActorRef>> senders = new HashMap<>();
private void addSender(Long userId, ActorRef actorRef){
if (senders.containsKey(userId)) {
final List<ActorRef> actors = senders.get(userId);
actors.add(actorRef);
senders.replace(userId, actors);
} else {
List<ActorRef> l = new ArrayList<>();
l.add(actorRef);
senders.put(userId, l);
}
}
private void removeSender(ActorRef actorRef){
for (List<ActorRef> refs : senders.values()) {
refs.remove(actorRef);
}
}
#Override
public void onReceive(Object message) throws Exception {
ActorRef sender = getSender();
// Handle messages sent to this 'router' here
if (message instanceof UserMessage) {
UserMessage userMessage = (UserMessage) message;
addSender(userMessage.userId, userMessage.actorRef);
// Watch sender so we can detect when they die.
getContext().watch(sender);
} else if (message instanceof Terminated) {
// One of our watched senders has died.
removeSender(sender);
} else {
unhandled(message);
}
}
}
Example
Now whenever you want to send a client with a websocket connection a message you can do something like:
ChatSenderController.java
private ActorRef chatSocketRouter;
#Inject
public ChatSenderController(#Named("chatSocketRouter") ActorRef chatInjectedActor) {
this.chatSocketRouter = chatInjectedActor;
}
public static void sendMessage(Long sendToId) {
// E.g. send the chat router a message that says hi
chatSocketRouter.tell(new Message(sendToId, "Hi"));
}
ChatSocketRouter.java
#Override
public void onReceive(Object message) throws Exception {
// ...
if (message instanceof Message) {
Message messageToSend = (Message) message;
// Loop through the list above and send the message to
// each connection. For example...
for (ActorRef wsConnection : senders.get(messageToSend.getSendToId())) {
// Send "Hi" to each of the other client's
// connected sessions
wsConnection.tell(messageToSend.getMessage());
}
}
// ...
}
Again, I wrote the above to help out those in need. After scouring the web I could not find a reasonable and simple example. There is an open issue for this exact topic. There are also some examples online but none of them were easy to follow. Akka has some great documentation but mixing it in with Play was a tough mental task.
Please help improve this answer if you see anything that is amiss.
I have created a cron job that start during application restart but when i tried to create db connection i am geeting null pointer exception. I am able to create and use db from other module using same configuration.
Below is my Application.conf
db.abc.driver=com.mysql.jdbc.Driver
db.abc.url="jdbc:mysql://localhost:3306/db_name?useSSL=false"
db.abc.username=root
db.abc.password=""
db.abc.autocommit=false
db.abc.isolation=READ_COMMITTED
And code that tried to access db is
public class SchduleJob extends AbstractModule{
#Override
protected void configure() {
bind(JobOne.class)
.to(JobOneImpl.class)
.asEagerSingleton();
} }
#ImplementedBy(JobOneImpl.class)
public interface JobOne {}
#Singleton
public class JobOneImpl implements JobOne {
final ActorSystem actorSystem = ActorSystem.create("name");
final ActorRef alertActor = actorSystem.actorOf(AlertActor.props);
public JobOneImpl() {
scheduleJobs();
}
private Cancellable scheduleJobs() {
return actorSystem.scheduler().schedule(
Duration.create(0, TimeUnit.MILLISECONDS), //Initial delay 0 milliseconds
Duration.create(6, TimeUnit.MINUTES), //Frequency 30 minutes
alertActor,
"alert",
actorSystem.dispatcher(),
null
);
}
}
public class AlertActor extends UntypedActor{
public static Props props = Props.create(AlertActor.class);
final ActorSystem actorSystem = ActorSystem.create("name");
final ActorRef messageActor = actorSystem.actorOf(MessageActor.props());
#Override
public void onReceive(Object message) throws Exception {
if(message != null && message instanceof String) {
RequestDAO requestDAO = new RequestDAO();
try {
List<DBRow> rows = requestDAO.getAllRow();
} catch(Exception exception) {
exception.printStackTrace();
}
}
}
}
public class RequestDAO {
public List<DBRow> getAllRow() throws Exception {
List<DBRow> rows = new ArrayList<DBRow>();
Connection connection = null;
try {
connection = DB.getDataSource("abc").getConnection();
connection.setAutoCommit(false);
} catch(Exception exception) {
exception.printStackTrace();
if(connection != null) {
connection.rollback();
} else {
System.out.println("in else***********");
}
return null;
} finally {
if(connection != null)
connection.close();
}
return schools;
}
When i am calling method getAllRow() of RequestDAO class it's throwing
java.lang.NullPointerException
at play.api.Application$$anonfun$instanceCache$1.apply(Application.scala:235)
at play.api.Application$$anonfun$instanceCache$1.apply(Application.scala:235)
at play.utils.InlineCache.fresh(InlineCache.scala:69)
at play.utils.InlineCache.apply(InlineCache.scala:55)
at play.api.db.DB$.db(DB.scala:22)
at play.api.db.DB$.getDataSource(DB.scala:41)
at play.api.db.DB.getDataSource(DB.scala)
at play.db.DB.getDataSource(DB.java:33)
But same code is working without cron job. What should i do to remove this error
Play uses the Typesafe config library for configuration.
I suspect your current working directory from the cron script isn't set, so it's probably not finding your application.conf (application.properties) file.
However, Config is nice in that it allows you to specify where to look for the file, either by its base name (to choose among .conf | .properties | .json extensions) or the filename including the extension on the java command line:
To specify the base name, use -Dconfig.resource=/path/to/application
To specify the full name, use -Dconfig.file=/path/to/application.properties
I am adding messages to rabbitmq queue using spring amqp template in my spring batch item writer.
public class AmqpAsynchRpcItemWriter<T> implements ItemWriter<T> {
protected String exchange;
protected String routingKey;
protected String queue;
protected String replyQueue;
protected RabbitTemplate template;
BlockingQueue<Object> blockingQueue;
public void onMessage(Object msgContent) {
try {
blockingQueue.put(msgContent);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void write(List<? extends T> items) throws Exception {
for (T item : items) {
Message message = MessageBuilder
.withBody(item.toString().getBytes())
.setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN)
.setReplyTo(this.replyQueue)
.setCorrelationId(item.toString().getBytes()).build();
template.send(this.exchange, this.routingKey, message);
}
for (T item : items) {
Object msg = blockingQueue.poll(60, TimeUnit.SECONDS);
if (msg instanceof Exception) {
throw (Exception) msg;
} else if (msg == null) {
System.out.println("reply timeout...");
break;
}
}
}
}
Messages are going to be processed on different remote servers. I am trying to handle the use case where if my message processing is failed (due to some exception) the step execution will be stopped.
I want to purge all the remaining messages in that queue so that remaining messages in queue should not be consumed and processed as they will also be failed.
If the step is failed, my item writer will again queue all the messages, so I need to purge all remaining message on any exception.
How can I purge the queue using spring amqp ?
I could do it using
admin.purgeQueue(this.queue, true);
I would use RabbitAdmin instead
http://docs.spring.io/autorepo/docs/spring-amqp-dist/1.3.4.RELEASE/api/org/springframework/amqp/rabbit/core/RabbitAdmin.html#purgeQueue%28java.lang.String,%20boolean%29
#Autowired private RabbitAdmin admin;
...
admin.purgeQueue("queueName", false);
you can use
AMQP.Queue.PurgeOk queuePurge(java.lang.String queue)
"See queuePurge:
http://www.rabbitmq.com/amqp-0-9-1-quickref.html#queue.purge"