
io.axoniq.eventstore.client.util.Broadcaster Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2017. AxonIQ
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.axoniq.eventstore.client.util;
import io.axoniq.platform.grpc.NodeInfo;
import io.grpc.stub.StreamObserver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
* Utility class for broadcasting messages to a number of nodes, and waiting until all replies have been received.
*
* @param The type of return messages expected from the broadcast
* @author Marc Gathier
*/
public class Broadcaster {
private static final Logger logger = LoggerFactory.getLogger(Broadcaster.class);
private final Collection destinations;
private final Action action;
private final Consumer onNextCallback;
/**
* Initialize the broadcaster to send to given {@code destinations} using the given {@code action}, invoking the
* given {@code onNextCallback} when replies are received.
*
* @param destinations The destinations to broadcast messages to
* @param action The action to take for each destination
* @param onNextCallback The callback to invoke when results are received
*/
public Broadcaster(Collection destinations, Action action, Consumer onNextCallback) {
this.destinations = destinations;
this.action = action;
this.onNextCallback = onNextCallback;
}
/**
* Send a broadcast, waiting at most the given {@code waitTime} for results to come back. This method returns when
* all responses have been received, or the timeout has been reached.
*
* @param timeout The amount of time to wait for all responses
* @param unit The unit of time
* @throws InterruptedException when the thread was interrupted while waiting
*/
public void broadcast(int timeout, TimeUnit unit) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(destinations.size());
destinations.forEach(node -> action.perform(node, new StreamObserver() {
@Override
public void onNext(T t) {
onNextCallback.accept(t);
}
@Override
public void onError(Throwable throwable) {
logger.warn("Error from: {}:{} - {}", node.getHostName(), node.getGrpcPort(), GrpcExceptionParser.parse(throwable).toString());
countDownLatch.countDown();
}
@Override
public void onCompleted() {
countDownLatch.countDown();
}
}));
if (unit != null) {
countDownLatch.await(timeout, unit);
}
}
/**
* Interface describing the action to take.
*
* @param The type of return message expected from the broadcast
*/
public interface Action {
/**
* Perform the action for the given {@code node}, which is expected to invoke the given {@code resultObserver}
* when results are received.
*
* @param node The node to perform the action for
* @param resultObserver The observer to report the results of the action
*/
void perform(NodeInfo node, StreamObserver resultObserver);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy