2012-02-09 21:21:31 +01:00
|
|
|
/**
|
2013-01-09 01:47:48 +01:00
|
|
|
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
|
2012-02-09 21:21:31 +01:00
|
|
|
*/
|
2012-05-22 11:37:09 +02:00
|
|
|
package docs.zeromq;
|
2012-02-09 21:21:31 +01:00
|
|
|
|
2012-09-26 10:56:25 +02:00
|
|
|
//#import-pub-socket
|
2012-02-09 21:21:31 +01:00
|
|
|
import akka.zeromq.Bind;
|
|
|
|
|
import akka.zeromq.ZeroMQExtension;
|
2012-09-26 10:56:25 +02:00
|
|
|
//#import-pub-socket
|
|
|
|
|
//#import-sub-socket
|
2012-02-09 21:21:31 +01:00
|
|
|
import akka.zeromq.Connect;
|
|
|
|
|
import akka.zeromq.Listener;
|
|
|
|
|
import akka.zeromq.Subscribe;
|
2012-09-26 10:56:25 +02:00
|
|
|
//#import-sub-socket
|
|
|
|
|
//#import-unsub-topic-socket
|
2012-02-09 21:21:31 +01:00
|
|
|
import akka.zeromq.Unsubscribe;
|
2012-09-26 10:56:25 +02:00
|
|
|
//#import-unsub-topic-socket
|
|
|
|
|
//#import-pub-topic
|
2012-12-14 18:25:04 +01:00
|
|
|
import akka.util.ByteString;
|
2012-02-09 21:21:31 +01:00
|
|
|
import akka.zeromq.ZMQMessage;
|
2012-09-26 10:56:25 +02:00
|
|
|
//#import-pub-topic
|
2012-02-09 21:21:31 +01:00
|
|
|
|
|
|
|
|
import akka.zeromq.HighWatermark;
|
|
|
|
|
import akka.zeromq.SocketOption;
|
|
|
|
|
import akka.zeromq.ZeroMQVersion;
|
|
|
|
|
|
2012-09-26 10:56:25 +02:00
|
|
|
//#import-health
|
2012-02-09 21:21:31 +01:00
|
|
|
import akka.actor.ActorRef;
|
|
|
|
|
import akka.actor.UntypedActor;
|
|
|
|
|
import akka.actor.Props;
|
|
|
|
|
import akka.event.Logging;
|
|
|
|
|
import akka.event.LoggingAdapter;
|
2013-05-02 17:12:36 +02:00
|
|
|
import org.junit.*;
|
2012-10-15 16:18:52 +02:00
|
|
|
import scala.concurrent.duration.Duration;
|
2012-02-09 21:21:31 +01:00
|
|
|
import akka.serialization.SerializationExtension;
|
|
|
|
|
import akka.serialization.Serialization;
|
|
|
|
|
import java.io.Serializable;
|
|
|
|
|
import java.lang.management.ManagementFactory;
|
2012-09-26 10:56:25 +02:00
|
|
|
//#import-health
|
2012-02-09 21:21:31 +01:00
|
|
|
|
|
|
|
|
import com.typesafe.config.ConfigFactory;
|
|
|
|
|
|
|
|
|
|
import java.lang.management.MemoryMXBean;
|
|
|
|
|
import java.lang.management.MemoryUsage;
|
|
|
|
|
import java.lang.management.OperatingSystemMXBean;
|
|
|
|
|
import java.util.Date;
|
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
|
|
|
|
|
|
|
import akka.actor.ActorSystem;
|
|
|
|
|
import akka.testkit.AkkaSpec;
|
2013-05-02 17:12:36 +02:00
|
|
|
import akka.testkit.AkkaJUnitActorSystemResource;
|
2012-02-09 21:21:31 +01:00
|
|
|
|
|
|
|
|
public class ZeromqDocTestBase {
|
|
|
|
|
|
2013-05-02 17:12:36 +02:00
|
|
|
@ClassRule
|
|
|
|
|
public static AkkaJUnitActorSystemResource actorSystemResource =
|
|
|
|
|
new AkkaJUnitActorSystemResource("ZeromqDocTest",
|
|
|
|
|
ConfigFactory.parseString("akka.loglevel=INFO").withFallback(AkkaSpec.testConf()));
|
2012-02-09 21:21:31 +01:00
|
|
|
|
2013-05-02 17:12:36 +02:00
|
|
|
private final ActorSystem system = actorSystemResource.getSystem();
|
2012-02-09 21:21:31 +01:00
|
|
|
|
2013-04-14 22:56:41 +02:00
|
|
|
@SuppressWarnings("unused")
|
2012-02-09 21:21:31 +01:00
|
|
|
@Test
|
|
|
|
|
public void demonstrateCreateSocket() {
|
|
|
|
|
Assume.assumeTrue(checkZeroMQInstallation());
|
|
|
|
|
|
|
|
|
|
//#pub-socket
|
2012-09-26 10:56:25 +02:00
|
|
|
ActorRef pubSocket = ZeroMQExtension.get(system).newPubSocket(
|
|
|
|
|
new Bind("tcp://127.0.0.1:1233"));
|
2012-02-09 21:21:31 +01:00
|
|
|
//#pub-socket
|
|
|
|
|
|
|
|
|
|
//#sub-socket
|
2013-04-14 22:56:41 +02:00
|
|
|
ActorRef listener = system.actorOf(Props.create(ListenerActor.class));
|
2012-09-26 10:56:25 +02:00
|
|
|
ActorRef subSocket = ZeroMQExtension.get(system).newSubSocket(
|
|
|
|
|
new Connect("tcp://127.0.0.1:1233"),
|
|
|
|
|
new Listener(listener), Subscribe.all());
|
2012-02-09 21:21:31 +01:00
|
|
|
//#sub-socket
|
|
|
|
|
|
|
|
|
|
//#sub-topic-socket
|
2012-09-26 10:56:25 +02:00
|
|
|
ActorRef subTopicSocket = ZeroMQExtension.get(system).newSubSocket(
|
|
|
|
|
new Connect("tcp://127.0.0.1:1233"),
|
|
|
|
|
new Listener(listener), new Subscribe("foo.bar"));
|
2012-02-09 21:21:31 +01:00
|
|
|
//#sub-topic-socket
|
|
|
|
|
|
|
|
|
|
//#unsub-topic-socket
|
2012-09-19 23:55:53 +02:00
|
|
|
subTopicSocket.tell(new Unsubscribe("foo.bar"), null);
|
2012-02-09 21:21:31 +01:00
|
|
|
//#unsub-topic-socket
|
|
|
|
|
|
|
|
|
|
byte[] payload = new byte[0];
|
|
|
|
|
//#pub-topic
|
2012-12-14 18:25:04 +01:00
|
|
|
pubSocket.tell(ZMQMessage.withFrames(ByteString.fromString("foo.bar"), ByteString.fromArray(payload)), null);
|
2012-02-09 21:21:31 +01:00
|
|
|
//#pub-topic
|
|
|
|
|
|
2012-11-29 14:46:42 +01:00
|
|
|
system.stop(subSocket);
|
|
|
|
|
system.stop(subTopicSocket);
|
|
|
|
|
|
2012-02-09 21:21:31 +01:00
|
|
|
//#high-watermark
|
|
|
|
|
ActorRef highWatermarkSocket = ZeroMQExtension.get(system).newRouterSocket(
|
2012-09-26 10:56:25 +02:00
|
|
|
new SocketOption[] { new Listener(listener),
|
|
|
|
|
new Bind("tcp://127.0.0.1:1233"), new HighWatermark(50000) });
|
2012-02-09 21:21:31 +01:00
|
|
|
//#high-watermark
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void demonstratePubSub() throws Exception {
|
|
|
|
|
Assume.assumeTrue(checkZeroMQInstallation());
|
|
|
|
|
|
|
|
|
|
//#health2
|
|
|
|
|
|
2013-04-14 22:56:41 +02:00
|
|
|
system.actorOf(Props.create(HealthProbe.class), "health");
|
2012-02-09 21:21:31 +01:00
|
|
|
//#health2
|
|
|
|
|
|
|
|
|
|
//#logger2
|
|
|
|
|
|
2013-04-14 22:56:41 +02:00
|
|
|
system.actorOf(Props.create(Logger.class), "logger");
|
2012-02-09 21:21:31 +01:00
|
|
|
//#logger2
|
|
|
|
|
|
|
|
|
|
//#alerter2
|
|
|
|
|
|
2013-04-14 22:56:41 +02:00
|
|
|
system.actorOf(Props.create(HeapAlerter.class), "alerter");
|
2012-02-09 21:21:31 +01:00
|
|
|
//#alerter2
|
|
|
|
|
|
2012-02-10 10:40:24 +01:00
|
|
|
// Let it run for a while to see some output.
|
|
|
|
|
// Don't do like this in real tests, this is only doc demonstration.
|
2012-02-09 21:21:31 +01:00
|
|
|
Thread.sleep(3000L);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean checkZeroMQInstallation() {
|
|
|
|
|
try {
|
|
|
|
|
ZeroMQVersion v = ZeroMQExtension.get(system).version();
|
2012-12-14 18:25:04 +01:00
|
|
|
return (v.major() >= 3 || (v.major() >= 2 && v.minor() >= 1));
|
2012-02-09 21:21:31 +01:00
|
|
|
} catch (LinkageError e) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-26 10:56:25 +02:00
|
|
|
static
|
2012-02-09 21:21:31 +01:00
|
|
|
//#listener-actor
|
2012-09-26 10:56:25 +02:00
|
|
|
public class ListenerActor extends UntypedActor {
|
2012-02-09 21:21:31 +01:00
|
|
|
public void onReceive(Object message) throws Exception {
|
|
|
|
|
//...
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//#listener-actor
|
|
|
|
|
|
2012-09-26 10:56:25 +02:00
|
|
|
static
|
2012-02-09 21:21:31 +01:00
|
|
|
//#health
|
2012-09-26 10:56:25 +02:00
|
|
|
public final Object TICK = "TICK";
|
2012-02-09 21:21:31 +01:00
|
|
|
|
2012-09-26 10:56:25 +02:00
|
|
|
//#health
|
|
|
|
|
static
|
|
|
|
|
//#health
|
|
|
|
|
public class Heap implements Serializable {
|
2013-04-14 22:56:41 +02:00
|
|
|
private static final long serialVersionUID = 1L;
|
2012-02-09 21:21:31 +01:00
|
|
|
public final long timestamp;
|
|
|
|
|
public final long used;
|
|
|
|
|
public final long max;
|
|
|
|
|
|
|
|
|
|
public Heap(long timestamp, long used, long max) {
|
|
|
|
|
this.timestamp = timestamp;
|
|
|
|
|
this.used = used;
|
|
|
|
|
this.max = max;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-26 10:56:25 +02:00
|
|
|
//#health
|
|
|
|
|
static
|
|
|
|
|
//#health
|
|
|
|
|
public class Load implements Serializable {
|
2013-04-14 22:56:41 +02:00
|
|
|
private static final long serialVersionUID = 1L;
|
2012-02-09 21:21:31 +01:00
|
|
|
public final long timestamp;
|
|
|
|
|
public final double loadAverage;
|
|
|
|
|
|
|
|
|
|
public Load(long timestamp, double loadAverage) {
|
|
|
|
|
this.timestamp = timestamp;
|
|
|
|
|
this.loadAverage = loadAverage;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-26 10:56:25 +02:00
|
|
|
//#health
|
|
|
|
|
static
|
|
|
|
|
//#health
|
|
|
|
|
public class HealthProbe extends UntypedActor {
|
2012-02-09 21:21:31 +01:00
|
|
|
|
2012-09-26 10:56:25 +02:00
|
|
|
ActorRef pubSocket = ZeroMQExtension.get(getContext().system()).newPubSocket(
|
|
|
|
|
new Bind("tcp://127.0.0.1:1237"));
|
2012-02-09 21:21:31 +01:00
|
|
|
MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
|
|
|
|
|
OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
|
|
|
|
|
Serialization ser = SerializationExtension.get(getContext().system());
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void preStart() {
|
|
|
|
|
getContext().system().scheduler()
|
2012-09-26 10:56:25 +02:00
|
|
|
.schedule(Duration.create(1, "second"), Duration.create(1, "second"),
|
2012-12-18 00:51:11 +01:00
|
|
|
getSelf(), TICK, getContext().dispatcher(), null);
|
2012-02-09 21:21:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void postRestart(Throwable reason) {
|
2012-02-10 10:40:24 +01:00
|
|
|
// don't call preStart, only schedule once
|
2012-02-09 21:21:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onReceive(Object message) {
|
|
|
|
|
if (message.equals(TICK)) {
|
|
|
|
|
MemoryUsage currentHeap = memory.getHeapMemoryUsage();
|
|
|
|
|
long timestamp = System.currentTimeMillis();
|
|
|
|
|
|
|
|
|
|
// use akka SerializationExtension to convert to bytes
|
2012-12-14 18:25:04 +01:00
|
|
|
ByteString heapTopic = ByteString.fromString("health.heap", "UTF-8");
|
|
|
|
|
ByteString heapPayload = ByteString.fromArray(
|
|
|
|
|
ser.serialize(
|
|
|
|
|
new Heap(timestamp,
|
|
|
|
|
currentHeap.getUsed(),
|
|
|
|
|
currentHeap.getMax())
|
|
|
|
|
).get());
|
2012-02-09 21:21:31 +01:00
|
|
|
// the first frame is the topic, second is the message
|
2012-12-14 18:25:04 +01:00
|
|
|
pubSocket.tell(ZMQMessage.withFrames(heapTopic, heapPayload), getSelf());
|
2012-02-09 21:21:31 +01:00
|
|
|
|
|
|
|
|
// use akka SerializationExtension to convert to bytes
|
2012-12-14 18:25:04 +01:00
|
|
|
ByteString loadTopic = ByteString.fromString("health.load", "UTF-8");
|
|
|
|
|
ByteString loadPayload = ByteString.fromArray(
|
|
|
|
|
ser.serialize(new Load(timestamp, os.getSystemLoadAverage())).get()
|
|
|
|
|
);
|
2012-02-09 21:21:31 +01:00
|
|
|
// the first frame is the topic, second is the message
|
2012-12-14 18:25:04 +01:00
|
|
|
pubSocket.tell(ZMQMessage.withFrames(loadTopic, loadPayload), getSelf());
|
2012-02-09 21:21:31 +01:00
|
|
|
} else {
|
|
|
|
|
unhandled(message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
//#health
|
|
|
|
|
|
2012-09-26 10:56:25 +02:00
|
|
|
static
|
2012-02-09 21:21:31 +01:00
|
|
|
//#logger
|
2012-09-26 10:56:25 +02:00
|
|
|
public class Logger extends UntypedActor {
|
2012-02-09 21:21:31 +01:00
|
|
|
|
2012-09-26 10:56:25 +02:00
|
|
|
ActorRef subSocket = ZeroMQExtension.get(getContext().system()).newSubSocket(
|
|
|
|
|
new Connect("tcp://127.0.0.1:1237"),
|
2012-02-09 21:21:31 +01:00
|
|
|
new Listener(getSelf()), new Subscribe("health"));
|
|
|
|
|
Serialization ser = SerializationExtension.get(getContext().system());
|
|
|
|
|
SimpleDateFormat timestampFormat = new SimpleDateFormat("HH:mm:ss.SSS");
|
|
|
|
|
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onReceive(Object message) {
|
|
|
|
|
if (message instanceof ZMQMessage) {
|
|
|
|
|
ZMQMessage m = (ZMQMessage) message;
|
2012-12-14 18:25:04 +01:00
|
|
|
String topic = m.frame(0).utf8String();
|
2012-02-09 21:21:31 +01:00
|
|
|
// the first frame is the topic, second is the message
|
2012-12-14 18:25:04 +01:00
|
|
|
if ("health.heap".equals(topic)) {
|
|
|
|
|
Heap heap = ser.deserialize(m.frame(1).toArray(), Heap.class).get();
|
2012-09-26 10:56:25 +02:00
|
|
|
log.info("Used heap {} bytes, at {}", heap.used,
|
|
|
|
|
timestampFormat.format(new Date(heap.timestamp)));
|
2012-12-14 18:25:04 +01:00
|
|
|
} else if ("health.load".equals(topic)) {
|
|
|
|
|
Load load = ser.deserialize(m.frame(1).toArray(), Load.class).get();
|
2012-09-26 10:56:25 +02:00
|
|
|
log.info("Load average {}, at {}", load.loadAverage,
|
|
|
|
|
timestampFormat.format(new Date(load.timestamp)));
|
2012-02-09 21:21:31 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
unhandled(message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//#logger
|
|
|
|
|
|
2012-09-26 10:56:25 +02:00
|
|
|
static
|
2012-02-09 21:21:31 +01:00
|
|
|
//#alerter
|
2012-09-26 10:56:25 +02:00
|
|
|
public class HeapAlerter extends UntypedActor {
|
2012-02-09 21:21:31 +01:00
|
|
|
|
2012-09-26 10:56:25 +02:00
|
|
|
ActorRef subSocket = ZeroMQExtension.get(getContext().system()).newSubSocket(
|
|
|
|
|
new Connect("tcp://127.0.0.1:1237"),
|
|
|
|
|
new Listener(getSelf()), new Subscribe("health.heap"));
|
2012-02-09 21:21:31 +01:00
|
|
|
Serialization ser = SerializationExtension.get(getContext().system());
|
|
|
|
|
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onReceive(Object message) {
|
|
|
|
|
if (message instanceof ZMQMessage) {
|
|
|
|
|
ZMQMessage m = (ZMQMessage) message;
|
2012-12-14 18:25:04 +01:00
|
|
|
String topic = m.frame(0).utf8String();
|
2012-02-09 21:21:31 +01:00
|
|
|
// the first frame is the topic, second is the message
|
2012-12-14 18:25:04 +01:00
|
|
|
if ("health.heap".equals(topic)) {
|
|
|
|
|
Heap heap = ser.<Heap>deserialize(m.frame(1).toArray(), Heap.class).get();
|
2012-02-09 21:21:31 +01:00
|
|
|
if (((double) heap.used / heap.max) > 0.9) {
|
|
|
|
|
count += 1;
|
|
|
|
|
} else {
|
|
|
|
|
count = 0;
|
|
|
|
|
}
|
|
|
|
|
if (count > 10) {
|
2012-09-26 10:56:25 +02:00
|
|
|
log.warning("Need more memory, using {} %",
|
|
|
|
|
(100.0 * heap.used / heap.max));
|
2012-02-09 21:21:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
unhandled(message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
//#alerter
|
|
|
|
|
|
|
|
|
|
}
|