use of io.mantisrx.common.network.Endpoint in project mantis by Netflix.
the class StageExecutorsGroupByTest method testExecuteIntermediatStage.
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void testExecuteIntermediatStage() throws InterruptedException {
// Note, this test has a timing issue, client starts
// sending data before server is ready, resulting
// in a RST (connection reset by peer)
TestGroupByJob provider = new TestGroupByJob();
Job<Pair> job = provider.getJobInstance();
List<StageConfig<?, ?>> stages = job.getStages();
PortSelectorWithinRange portSelector = new PortSelectorWithinRange(8000, 9000);
final int publishPort = portSelector.acquirePort();
final int consumerPort = portSelector.acquirePort();
Observable<Observable<GroupedObservable<String, Integer>>> go = Observable.just(Observable.range(0, 10).groupBy(new Func1<Integer, String>() {
@Override
public String call(Integer t1) {
if ((t1 % 2) == 0) {
return "even";
} else {
return "odd";
}
}
}));
// mimic previous stage with a server
ServeGroupedObservable<String, Integer> config = new ServeGroupedObservable.Builder<String, Integer>().keyEncoder(Codecs.string()).valueEncoder(Codecs.integer()).observable(go).build();
RemoteRxServer server = new RemoteRxServer.Builder().addObservable(config).port(consumerPort).build();
server.start();
EndpointInjector staticEndpoints = new EndpointInjector() {
@Override
public Observable<EndpointChange> deltas() {
return Observable.create(new OnSubscribe<EndpointChange>() {
@Override
public void call(Subscriber<? super EndpointChange> subscriber) {
subscriber.onNext(new EndpointChange(EndpointChange.Type.add, new Endpoint("localhost", consumerPort, "0")));
subscriber.onNext(new EndpointChange(EndpointChange.Type.add, new Endpoint("localhost", consumerPort, "1")));
subscriber.onCompleted();
}
});
}
};
WorkerConsumer consumer = new WorkerConsumerRemoteObservable(null, staticEndpoints);
WorkerPublisher producer = new WorkerPublisherRemoteObservable(publishPort, null, Observable.just(1), null);
// execute source
StageExecutors.executeIntermediate(consumer, stages.get(1), producer, new Context());
ConnectToGroupedObservable<String, Integer> connectConfig = new ConnectToGroupedObservable.Builder<String, Integer>().host("localhost").port(publishPort).keyDecoder(Codecs.string()).valueDecoder(Codecs.integer()).build();
Iterator<GroupedObservable<String, Integer>> iter = RemoteObservable.connect(connectConfig).getObservable().toBlocking().getIterator();
// verify numbers are grouped by even/odd
// even is first due to zero
GroupedObservable<String, Integer> even = iter.next();
Assert.assertEquals("even", even.getKey());
Iterator<Integer> evenIter = even.toBlocking().getIterator();
Assert.assertEquals(0, evenIter.next().intValue());
Assert.assertEquals(4, evenIter.next().intValue());
Assert.assertEquals(16, evenIter.next().intValue());
Assert.assertEquals(36, evenIter.next().intValue());
GroupedObservable<String, Integer> odd = iter.next();
Assert.assertEquals("odd", odd.getKey());
Iterator<Integer> oddIter = odd.toBlocking().getIterator();
Assert.assertEquals(1, oddIter.next().intValue());
Assert.assertEquals(9, oddIter.next().intValue());
Assert.assertEquals(25, oddIter.next().intValue());
Assert.assertEquals(49, oddIter.next().intValue());
// should only have two groups
Assert.assertEquals(false, iter.hasNext());
}
use of io.mantisrx.common.network.Endpoint in project mantis by Netflix.
the class StageExecutorsTest method testExecuteIntermediatStage.
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void testExecuteIntermediatStage() throws InterruptedException {
TestJob provider = new TestJob();
Job<Integer> job = provider.getJobInstance();
List<StageConfig<?, ?>> stages = job.getStages();
PortSelectorWithinRange portSelector = new PortSelectorWithinRange(8000, 9000);
final int publishPort = portSelector.acquirePort();
final int consumerPort = portSelector.acquirePort();
// mimic previous stage with a server
RemoteRxServer server1 = RemoteObservable.serve(consumerPort, Observable.range(0, 10), Codecs.integer());
server1.start();
EndpointInjector staticEndpoints = new EndpointInjector() {
@Override
public Observable<EndpointChange> deltas() {
return Observable.create(new OnSubscribe<EndpointChange>() {
@Override
public void call(Subscriber<? super EndpointChange> subscriber) {
subscriber.onNext(new EndpointChange(EndpointChange.Type.add, new Endpoint("localhost", consumerPort, "1")));
subscriber.onCompleted();
}
});
}
};
WorkerConsumer consumer = new WorkerConsumerRemoteObservable(null, staticEndpoints);
WorkerPublisher producer = new WorkerPublisherRemoteObservable(publishPort, null, Observable.just(1), null);
// execute intermediate, flatten results
StageExecutors.executeIntermediate(consumer, stages.get(1), producer, new Context());
Iterator<Integer> iter = RemoteObservable.connect(new ConnectToObservable.Builder<Integer>().host("localhost").slotId("0").port(publishPort).decoder(Codecs.integer()).build()).getObservable().toBlocking().getIterator();
// verify numbers are even
Assert.assertEquals(0, iter.next().intValue());
Assert.assertEquals(2, iter.next().intValue());
Assert.assertEquals(4, iter.next().intValue());
}
use of io.mantisrx.common.network.Endpoint in project mantis by Netflix.
the class StageExecutorsTest method testExecuteSink.
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void testExecuteSink() throws InterruptedException {
TestJob provider = new TestJob();
Job<Integer> job = provider.getJobInstance();
List<StageConfig<?, ?>> stages = job.getStages();
PortSelectorWithinRange portSelector = new PortSelectorWithinRange(8000, 9000);
final int consumerPort = portSelector.acquirePort();
// mimic previous stage with a server
RemoteRxServer server1 = RemoteObservable.serve(consumerPort, Observable.range(0, 10), Codecs.integer());
server1.start();
EndpointInjector staticEndpoints = new EndpointInjector() {
@Override
public Observable<EndpointChange> deltas() {
return Observable.create(new OnSubscribe<EndpointChange>() {
@Override
public void call(Subscriber<? super EndpointChange> subscriber) {
subscriber.onNext(new EndpointChange(EndpointChange.Type.add, new Endpoint("localhost", consumerPort, "1")));
subscriber.onCompleted();
}
});
}
};
Action0 noOpAction = new Action0() {
@Override
public void call() {
}
};
Action1<Throwable> noOpError = new Action1<Throwable>() {
@Override
public void call(Throwable t) {
}
};
WorkerConsumer consumer = new WorkerConsumerRemoteObservable(null, staticEndpoints);
// execute source
StageExecutors.executeSink(consumer, stages.get(1), job.getSink(), new TestPortSelector(), new RxMetrics(), new Context(), noOpAction, null, null, noOpAction, noOpError);
Iterator<Integer> iter = provider.getItemsWritten().iterator();
// verify numbers are even
Assert.assertEquals(0, iter.next().intValue());
Assert.assertEquals(2, iter.next().intValue());
Assert.assertEquals(4, iter.next().intValue());
}
use of io.mantisrx.common.network.Endpoint in project mantis by Netflix.
the class DynamicConnectionSet method observables.
public Observable<Observable<T>> observables() {
return endpointInjector.deltas().doOnCompleted(() -> logger.info("onComplete on injector deltas")).doOnError(t -> logger.error("caught unexpected error {}", t.getMessage(), t)).doOnSubscribe(new Action0() {
@Override
public void call() {
logger.info("Subscribing, clearing active connection set");
resetActiveConnections();
}
}).groupBy(new Func1<EndpointChange, String>() {
@Override
public String call(EndpointChange t1) {
return Endpoint.uniqueHost(t1.getEndpoint().getHost(), t1.getEndpoint().getPort(), t1.getEndpoint().getSlotId());
}
}).flatMap(new Func1<GroupedObservable<String, EndpointChange>, Observable<Observable<T>>>() {
@Override
public Observable<Observable<T>> call(final GroupedObservable<String, EndpointChange> group) {
final PublishSubject<Integer> closeConnectionTrigger = PublishSubject.create();
return group.doOnNext(new Action1<EndpointChange>() {
@Override
public void call(EndpointChange change) {
// side effect to force complete
if (EndpointChange.Type.complete == change.getType() && activeConnectionsContains(group.getKey(), change.getEndpoint())) {
logger.info("Received complete request, removing connection from active set, " + change.getEndpoint().getHost() + " port: " + change.getEndpoint().getPort() + " id: " + change.getEndpoint().getSlotId());
forceCompletedConnections.increment();
removeConnection(group.getKey(), change.getEndpoint());
closeConnectionTrigger.onNext(1);
}
}
}).filter(new Func1<EndpointChange, Boolean>() {
@Override
public Boolean call(EndpointChange change) {
// active connection check is to ensure
// latent adds are not allowed. This can
// occur if dynamicConnection set
// and reconciliator are chained together.
// Reconciliator will "see" changes
// before dynamic connection set add will
// assume connection is missing from set
boolean contains = activeConnectionsContains(group.getKey(), change.getEndpoint());
if (contains) {
logger.info("Skipping latent add for endpoint, already in active set: " + change);
}
return EndpointChange.Type.add == change.getType() && !contains;
}
}).map(new Func1<EndpointChange, Observable<T>>() {
@Override
public Observable<T> call(final EndpointChange toAdd) {
logger.info("Received add request, adding connection to active set, " + toAdd.getEndpoint().getHost() + " port: " + toAdd.getEndpoint().getPort() + ", with client id: " + toAdd.getEndpoint().getSlotId());
addConnection(group.getKey(), toAdd.getEndpoint());
Action0 disconnectCallback = new Action0() {
@Override
public void call() {
int timeToWait = random.nextInt((maxTimeoutOnUnexpectedTerminateSec - minTimeoutOnUnexpectedTerminateSec) + 1) + minTimeoutOnUnexpectedTerminateSec;
logger.info("Connection disconnected, waiting " + timeToWait + " seconds before removing from active set of connections: " + toAdd);
Observable.timer(timeToWait, TimeUnit.SECONDS).doOnCompleted(new Action0() {
@Override
public void call() {
logger.warn("Removing connection from active set, " + toAdd);
closedConnections.increment();
removeConnection(group.getKey(), toAdd.getEndpoint());
}
}).subscribe();
}
};
RemoteRxConnection<T> connection = toObservableFunc.call(toAdd.getEndpoint(), disconnectCallback, closeConnectionTrigger);
return connection.getObservable().doOnCompleted(toAdd.getEndpoint().getCompletedCallback()).doOnError(toAdd.getEndpoint().getErrorCallback());
}
});
}
});
}
use of io.mantisrx.common.network.Endpoint in project mantis by Netflix.
the class Reconciliator method startReconciliation.
private void startReconciliation() {
if (startedReconciliation.compareAndSet(false, true)) {
logger.info("Starting reconciliation for name: " + name);
running.increment();
subscription = Observable.combineLatest(currentExpectedSet, connectionSet.activeConnections(), new Func2<Set<Endpoint>, Set<Endpoint>, Void>() {
@Override
public Void call(Set<Endpoint> expected, Set<Endpoint> actual) {
reconciliationCheck.increment();
boolean check = expected.equals(actual);
logger.debug("Check result: " + check + ", size expected: " + expected.size() + " actual: " + actual.size() + ", for values expected: " + expected + " versus actual: " + actual);
if (!check) {
// reconcile adds
Set<Endpoint> expectedDiff = new HashSet<Endpoint>(expected);
expectedDiff.removeAll(actual);
if (expectedDiff.size() > 0) {
for (Endpoint endpoint : expectedDiff) {
logger.info("Connection missing from expected set, adding missing connection: " + endpoint);
reconciledChanges.onNext(new EndpointChange(Type.add, endpoint));
}
}
// reconile removes
Set<Endpoint> actualDiff = new HashSet<Endpoint>(actual);
actualDiff.removeAll(expected);
if (actualDiff.size() > 0) {
for (Endpoint endpoint : actualDiff) {
logger.info("Unexpected connection in active set, removing connection: " + endpoint);
reconciledChanges.onNext(new EndpointChange(Type.complete, endpoint));
}
}
}
return null;
}
}).onErrorResumeNext(new Func1<Throwable, Observable<? extends Void>>() {
@Override
public Observable<? extends Void> call(Throwable throwable) {
logger.error("caught error in Reconciliation for {}", name, throwable);
return Observable.empty();
}
}).doOnCompleted(new Action0() {
@Override
public void call() {
logger.error("onComplete in Reconciliation observable chain for {}", name);
stopReconciliation();
}
}).subscribe();
} else {
logger.info("reconciliation already started for {}", name);
}
}
Aggregations