Dynamic Merge of Infinite Reactor streams - reactive-programming

Usecase:
There is a module which Listens for events in synchronous mode. In the same module using the EmitterProccessor, the event is converted to Flux and made as infinite stream of events. Now there is a upstream module which can subscribes for these event streams. The problem here is how can I dynamically merge these streams to one and then subscribe in a single stream. A simple example is, let us say there are N number of sensors, we can dynamically register these sensors and start listening for measurements as stream of data in single stream after merging them into one stream. Here is the code sample written to mock this behavior.
Create callback and start listening for events
public interface CallBack {
void callBack(int name);
void done();
}
#Slf4j
#RequiredArgsConstructor
public class CallBackService {
private CallBack callBack;
private final Function<Integer, Integer> func;
public void register(CallBack intf) {
this.callBack = intf;
}
public void startServer() {
log.info("Callback started..");
IntStream.range(0, 10).forEach(i -> {
callBack.callBack(func.apply(i));
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
log.info("Callback finished..");
callBack.done();
}
}
Convert the events to streams using event proccessor
#Slf4j
public class EmitterService implements CallBack {
private EmitterProcessor<Integer> emitterProcessor;
public EmitterService(){
emitterProcessor = EmitterProcessor.create();
}
public EmitterProcessor<Integer> getEmmitor() {
return emitterProcessor;
}
#Override
public void callBack(int name) {
log.info("callbakc {} invoked", name);
//fluxSink.next(name);
emitterProcessor.onNext(name);
}
public void done() {
//fluxSink.complete();
emitterProcessor.onComplete();
}
}
public class WrapperService {
EmitterService service1;
ExecutorService service2;
public Flux<Integer> startService(Function<Integer, Integer> func) {
CallBackService service = new CallBackService(func);
service1 = new EmitterService();
service.register(service1);
service2 = Executors.newSingleThreadExecutor();
service2.submit(service::startServer);
return service1.getEmmitor();
}
public void shutDown() {
service1.getEmmitor().onComplete();
service2.shutdown();
}
}
Subscribe for the events
#Slf4j
public class MainService {
public static void main(String[] args) throws InterruptedException {
TopicProcessor<Integer> stealer = TopicProcessor.<Integer>builder().share(true).build();
CountDownLatch latch = new CountDownLatch(20);
WrapperService n1 =new WrapperService();
WrapperService n2 =new WrapperService();
// n1.startService(i->i).mergeWith(n2.startService(i->i*2)).subscribe(stealer);
n1.startService(i->i).subscribe(stealer);
n2.startService(i->i*2).subscribe(stealer);
stealer.subscribeOn(Schedulers.boundedElastic())
.subscribe(x->{
log.info("Stole=>{}", x);
latch.countDown();
log.info("Latch count=>{}", latch.getCount());
});
latch.await();
n1.shutDown();
n2.shutDown();
stealer.shutdown();
}
}
Tried to use TopicProccessor with no success. In the above code subscription happens for first source, for second source there is no subscription. however if use n1.startService(i->i).mergeWith(n2.startService(i->i*2)).subscribe(stealer); subscription works, but there is no dynamic behavior in this case. Need to change subscriber every time.

Related

Flink - KafkaSink not writing data to kafka topic

I'm trying to read JSON events from Kafka, aggregate it on a eventId and its category and write them to a different kafka topic through flink. The program is able to read messages from kafka, but KafkaSink is not writing the data back to the other kafka topic. I'm not sure on the mistake I'm doing. Can someone please check and let me know, where I'm wrong. Here is the code I'm using.
KafkaSource<EventMessage> source = KafkaSource.<EventMessage>builder()
.setBootstrapServers(LOCAL_KAFKA_BROKER)
.setTopics(INPUT_KAFKA_TOPIC)
.setGroupId(LOCAL_GROUP)
.setStartingOffsets(OffsetsInitializer.earliest())
.setValueOnlyDeserializer(new InputDeserializationSchema())
.build();
WindowAssigner<Object, TimeWindow> windowAssigner = TumblingEventTimeWindows.of(WINDOW_SIZE);
DataStream<EventMessage> eventStream = env.fromSource(source, WatermarkStrategy.noWatermarks(), "Event Source");
DataStream<EventSummary> events =
eventStream
.keyBy(eventMessage -> eventMessage.getCategory() + eventMessage.getEventId())
.window(windowAssigner)
.aggregate(new EventAggregator())
.name("EventAggregator test >> ");
KafkaSink<EventSummary> sink = KafkaSink.<EventSummary>builder()
.setBootstrapServers(LOCAL_KAFKA_BROKER)
.setRecordSerializer(KafkaRecordSerializationSchema.builder()
.setTopic(OUTPUT_KAFKA_TOPIC)
.setValueSerializationSchema(new OutputSummarySerializationSchema())
.build())
.setDeliverGuarantee(DeliveryGuarantee.AT_LEAST_ONCE)
.build();
events.sinkTo(sink);
These are the POJO's I've created for input message and output.
# EventMessage POJO
public class EventMessage implements Serializable {
private Long timestamp;
private int eventValue;
private String eventId;
private String category;
public EventMessage() { }
public EventMessage(Long timestamp, int eventValue, String eventId, String category) {
this.timestamp = timestamp;
this.eventValue = eventValue;
this.eventId = eventId;
this.category = category;
}
.....
}
# EventSummary POJO
public class EventSummary {
public EventMessage eventMessage;
public int sum;
public int count;
public EventSummary() { }
....
}
These are the deserialization and serialization schemas I'm using.
public class InputDeserializationSchema implements DeserializationSchema<EventMessage> {
static ObjectMapper objectMapper = new ObjectMapper();
#Override
public EventMessage deserialize(byte[] bytes) throws IOException {
return objectMapper.readValue(bytes, EventMessage.class);
}
#Override
public boolean isEndOfStream(EventMessage inputMessage) {
return false;
}
#Override
public TypeInformation<EventMessage> getProducedType() {
return TypeInformation.of(EventMessage.class);
}
}
public class OutputSummarySerializationSchema implements SerializationSchema<EventSummary> {
static ObjectMapper objectMapper = new ObjectMapper();
Logger logger = LoggerFactory.getLogger(OutputSummarySerializationSchema.class);
#Override
public byte[] serialize(EventSummary eventSummary) {
if (objectMapper == null) {
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
objectMapper = new ObjectMapper();
}
try {
String json = objectMapper.writeValueAsString(eventSummary);
return json.getBytes();
} catch (com.fasterxml.jackson.core.JsonProcessingException e) {
logger.error("Failed to parse JSON", e);
}
return new byte[0];
}
}
I'm using this aggregator for aggregating the JSON messages.
public class EventAggregator implements AggregateFunction<EventMessage, EventSummary, EventSummary> {
private static final Logger log = LoggerFactory.getLogger(EventAggregator.class);
#Override
public EventSummary createAccumulator() {
return new EventSummary();
}
#Override
public EventSummary add(EventMessage eventMessage, EventSummary eventSummary) {
eventSummary.eventMessage = eventMessage;
eventSummary.count += 1;
eventSummary.sum += eventMessage.getEventValue();
return eventSummary;
}
#Override
public EventSummary getResult(EventSummary eventSummary) {
return eventSummary;
}
#Override
public EventSummary merge(EventSummary summary1, EventSummary summary2) {
return new EventSummary(null,
summary1.sum + summary2.sum,
summary1.count + summary2.count);
}
}
Can someone help me on this?
Thanks in advance.
In order for event time windowing to work, you must specify a proper WatermarkStrategy. Otherwise, the windows will never close, and no results will be produced.
The role that watermarks play is to mark a place in a stream, and indicate that the stream is, at that point, complete through some specific timestamp. Until receiving this indicator of stream completeness, windows continue to wait for more events to be assigned to them.
To simply the debugging the watermarks, you might switch to a PrintSink until you get the watermarking working properly. Or to simplify debugging the KafkaSink, you could switch to using processing time windows until the sink is working.

Unsubscribing from RxJava2/RxAndroid PublishSubject

I'm trying to replace EventBus with RxAndroid.
I want pageable fragments to subscribe/unsubscribe to an event source, these fragments get created and discarded relatively quickly, depending on how fast the user slides to a new page.
In EventBus I was able to add an decorated callback method (ie #Subscribe(threadMode = ThreadMode.MAIN)) and register/unregister in the onStart/onStop methods of the fragment.
With RxJava2 I now create a PublishSubject object in a class
public static PublishSubject<List<Long>> m_psUpdatedDays = PublishSubject.create();
public static void publishUpdatedDays(List<Long> lDay) {
m_psUpdatedDays.onNext(lDay);
}
and subscribe to this publisher in another class by calling the following in the Fragment's onStart method:
m_psUpdatedDays.observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<List<Long>>() {
#Override public void onSubscribe(Disposable d) {}
#Override public void onNext(List<Long> longs) {
...
Update Fragment UI here
...
}
#Override public void onError(Throwable e) {}
#Override public void onComplete() {}
});
My question is how can I unsubscribe this new Observer when the Fragment's onStop method is called by the system?
Do I need to store the Disposable object which I get in the onSubscribe and then call .dispose() on it in the onStop method?
You can make use of a CompositeDisposable object, which can keep a list of disposables and all of them can be disposed together.
Create a CompositeDisposable instance in the base fragment level, keep on adding your disposables into it.
public abstract class BaseFragment extends Fragment {
protected CompositeDisposable mCompositeDisposable = new CompositeDisposable();
#Override
public void onPause() {
super.onPause();
mCompositeDisposable.clear();
//clear will clear all, but can accept new disposable.
// You can call it on `onPause` or `orDestroyView` events.
}
#Override
public void onDestroy() {
super.onDestroy();
mCompositeDisposable.dispose();
//dispose will clear all and set isDisposed = true, so it will not accept any new disposable
}
}
In your fragments, subscribe to the Observable using the subscribeWith method, which gives you a disposable instantly and this disposable you can dispose later in the onPause or onDestroy events (wherever you want)
public class MyFragment extends BaseFragment {
#Override
public void onStart() {
super.onStart();
Disposable disposable = m_psUpdatedDays.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<List<Long>>() { // Use `subscribeWith` instead of `subscribe`, which will give you back the disposable , which can be disposed later
#Override
public void onNext(List<Long> longs) {
// Update Fragment UI here
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
mCompositeDisposable.add(disposable); // add the disposable to the disposable list
}
}

Guava EventBus Multiple subscribers same tpe

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
public class Test {
public static class Processing { }
public static class ProcessingResults { }
public static class ProcessingFinished { }
public static EventBus bus = new EventBus();
#Subscribe
public void receiveStartRequest(Processing evt) {
System.out.println("Got processing request - starting processing");
}
#Subscribe
public void processingStarted(Processing evt) {
System.out.println("Processing has started");
}
#Subscribe
public void resultsReceived(ProcessingResults evt) {
System.out.println("got results");
}
#Subscribe
public void processingComplete(ProcessingFinished evt) {
System.out.println("Processing has completed");
}
public static void main(String[] args) {
Test t = new Test();
bus.register(t);
bus.post(new Processing());
}
}
So, in above example, it can be seen that there are 2 subscribers accepting same type Processing. Now, at the time of post(), which all functions will get called? If the 2 functions receiveStartRequest and processingStarted will get called, then in which order they will be get called?
Both your methods will be called and in no predefinite order.
To counter this, just create two extra classes: ProcessingStarted and ProcessingRequested.
public class ProcessingStarted {
private Processing processing;
// Constructors
// Getters/Setters
}
public class ProcessingStarted {
private Processing processing;
// Constructors
// Getters/Setters
}
Then call post(new ProcessingRequested(processing)) and post(new ProcessingStarted(processing)) when needed, instead of a single post(processing).

Where to setup my actors in a play app?

I want to setup my actors inside of a play app, for example, I have an actor that will poll a message queue or run every x minutes.
I renamed the actor system in my play app, so I now how to get the actor system.
play.akka.actor-system = "myAkka"
I know I can get the actor system using dependency injection inside of a controller but I don't need it at the controller level, I need to do this when my application starts outside of the request/response level.
One of the the way is to crate your actors in an eager singleton.
Create singleton like this:
package com.app;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import javax.inject.Inject;
import javax.inject.Singleton;
#Singleton
public class ActorBootstrap {
private ActorRef somaActor;
#Inject
public ActorBootstrap(ActorSystem system) {
// Craete actors here: somaActor = system.actorOf()
}
public ActorRef getSomaActor() {
return somaActor;
}
}
Define the singleton as eager in guice module as follows:
package com.app;
import com.google.inject.AbstractModule;
public class AppModule extends AbstractModule {
#Override
protected void configure() {
bind(ActorBootstrap.class).asEagerSingleton();
}
}
See https://www.playframework.com/documentation/2.5.x/JavaDependencyInjection#Eager-bindings for details.
Register your module with Play (add the following line to application.conf):
play.modules.enabled += "com.app.AppModule"
See https://www.playframework.com/documentation/2.5.x/JavaDependencyInjection#Programmatic-bindings for details.
Here is a basic example of a scheduled actor implementation.
The actor schedules some periodic work:
public class ScheduledActor extends AbstractActor {
// Protocol
private static final String CANCEL = "cancel";
private static final String TICK = "tick";
// The first polling in 30 sec after the start
private static final int TICK_INTERVAL_SEC = 90;
private static final int TICK_INTERVAL_SEC = 90;
private Cancellable scheduler;
public static Props props() {
return Props.create(ScheduledActor.class, ()->new ScheduledActor());
}
public ScheduledActor() {
receive(ReceiveBuilder
.matchEquals(TICK, m -> onTick())
.matchEquals(CANCEL, this::cancelTick)
.matchAny(this::unhandled)
.build());
}
#Override
public void preStart() throws Exception {
getContext().system().scheduler().scheduleOnce(
Duration.create(ON_START_POLL_INTERVAL, TimeUnit.SECONDS),
self(),
TICK,
getContext().dispatcher(),
null);
}
#Override
public void postRestart(Throwable reason) throws Exception {
// No call to preStart
}
private void onTick() {
// do here the periodic stuff
...
getContext().system().scheduler().scheduleOnce(
Duration.create(TICK_INTERVAL_SEC, TimeUnit.SECONDS),
self(),
TICK,
getContext().dispatcher(),
null);
}
public void cancelTick(String string) {
if (scheduler != null) {
scheduler.cancel();
}
}
}
The actor life-cycle handler creates and actor and cancels it upon application stop:
public class ScheduledActorMonitor {
private ActorRef scheduler;
private ActorSystem system;
#Inject
public ScheduledActorMonitor(ActorSystem system, ApplicationLifecycle lifeCycle) {
this.system = system;
initStopHook(lifeCycle);
}
public void startPolling() {
scheduler = system.actorOf(ScheduledActor.props();
}
public void cancelTick() {
if (scheduler != null) {
scheduler.tell(HelloScheduler.CANCEL, null);
}
}
private void initStopHook(ApplicationLifecycle lifeCycle) {
lifeCycle.addStopHook(() -> {
cancelTick();
return CompletableFuture.completedFuture(null);
});
}
}
The StartupHandler is injected as a singleton; it receives in the constructor an actor monitor and starts polling:
#Singleton
public class StartupHandler {
#Inject
public StartupHandler(final ScheduledActorMonitor schedularMonitor) {
schedularMonitor.startPolling();
}
}
The StartupHandler is registered for injection by the default module Play Module:
public class Module extends AbstractModule {
#Override
public void configure() {
bind(StartupHandler.class).asEagerSingleton();
}
}
You can read more here.

Guava EventBus: pause event posting

Is there any way to pause event posting by the EventBus from the guava library.
I have a method changeSomething() that posts an event (e.g. SomethingChangedEvent). Now this method is called in a loop by another method doStuff().
The problem is that the SomethingChangedEvent is posted on every call to changeSomething() even though only the last change matters. Due to the fact that the handlers of the event execute some heavy-weight calculations, the performance of the application degrades fast.
After the last time changeSomething() is executed I would like to tell guava to resume event processing.
Is there any way to tell guava to ignore all SomethingChangedEvents except the very last one?
I tried this pattern, derived from the poison pill pattern using sub-classing :
public class SomethingChangedEvent {
private final String name;
public SomethingChangedEvent(String name) {
this.name = name;
}
#Override
public String toString() {
return name;
}
}
public class IgnoreSomethingChangedEvent extends SomethingChangedEvent {
public IgnoreSomethingChangedEvent(String name) {
super(name);
}
}
public class HandleSomethingChangedEvent extends SomethingChangedEvent {
public HandleSomethingChangedEvent(String name) {
super(name);
}
}
private void eventBusTest() {
EventBus eventBus = new EventBus();
eventBus.register(new EventBusSomethingChanged());
eventBus.post(new SomethingChangedEvent("process this one"));
eventBus.post(new IgnoreSomethingChangedEvent("ignore"));
eventBus.post(new SomethingChangedEvent("don't process this one"));
eventBus.post(new HandleSomethingChangedEvent("handle"));
eventBus.post(new SomethingChangedEvent("process this one bis"));
}
public class EventBusSomethingChanged {
private boolean ignore;
#Subscribe
public void SomethingChanged(SomethingChangedEvent e) {
if (e instanceof IgnoreSomethingChangedEvent) {
ignore = true;
return;
}
if (e instanceof HandleSomethingChangedEvent) {
ignore = false;
return;
}
if (!ignore) {
System.out.println("processing:" + e);
}
}
}