use of com.hedera.mirror.monitor.NodeProperties in project hedera-mirror-node by hashgraph.
the class TransactionPublisher method getClients.
private synchronized Flux<Client> getClients() {
NodeValidationProperties validationProperties = monitorProperties.getNodeValidation();
var configuredNodes = monitorProperties.getNodes();
Map<String, AccountId> nodeMap = configuredNodes.stream().collect(Collectors.toMap(NodeProperties::getEndpoint, p -> AccountId.fromString(p.getAccountId())));
this.nodes.addAll(configuredNodes);
Client client = toClient(nodeMap);
client.setMaxAttempts(validationProperties.getMaxAttempts());
client.setMaxBackoff(validationProperties.getMaxBackoff());
client.setMinBackoff(validationProperties.getMinBackoff());
client.setRequestTimeout(validationProperties.getRequestTimeout());
this.validationClient.set(client);
if (validationProperties.isEnabled() && nodeValidator.get() == null) {
int nodeCount = configuredNodes.size();
int parallelism = Math.min(nodeCount, validationProperties.getMaxThreads());
var scheduler = Schedulers.newParallel("validator", parallelism + 1);
var disposable = Flux.interval(Duration.ZERO, validationProperties.getFrequency(), scheduler).filter(// In case it's later disabled
i -> validationProperties.isEnabled()).flatMap(i -> Flux.fromIterable(configuredNodes)).parallel(parallelism).runOn(scheduler).map(this::validateNode).sequential().buffer(nodeCount).doOnNext(i -> log.info("{} of {} nodes are functional", nodes.size(), nodeCount)).doOnSubscribe(s -> log.info("Starting node validation")).onErrorContinue((e, i) -> log.error("Exception validating nodes: ", e)).subscribe();
nodeValidator.set(disposable);
}
return Flux.range(0, publishProperties.getClients()).flatMap(i -> Mono.defer(() -> Mono.just(toClient(nodeMap))));
}
use of com.hedera.mirror.monitor.NodeProperties in project hedera-mirror-node by hashgraph.
the class TransactionPublisherTest method setup.
@BeforeEach
void setup() throws IOException {
publishScenarioProperties = new PublishScenarioProperties();
publishScenarioProperties.setName("test");
publishScenarioProperties.setType(TransactionType.CRYPTO_TRANSFER);
monitorProperties = new MonitorProperties();
monitorProperties.setNodes(Set.of(new NodeProperties("0.0.3", "in-process:test")));
monitorProperties.getNodeValidation().setEnabled(false);
OperatorProperties operatorProperties = monitorProperties.getOperator();
operatorProperties.setAccountId("0.0.100");
operatorProperties.setPrivateKey(PrivateKey.generate().toString());
publishProperties = new PublishProperties();
transactionPublisher = new TransactionPublisher(monitorProperties, publishProperties);
cryptoServiceStub = new CryptoServiceStub();
server = InProcessServerBuilder.forName("test").addService(cryptoServiceStub).directExecutor().build().start();
}
use of com.hedera.mirror.monitor.NodeProperties in project hedera-mirror-node by hashgraph.
the class TransactionPublisherTest method someValidNodes.
@Test
@Timeout(3)
void someValidNodes() {
NodeProperties node1 = new NodeProperties("0.0.3", "in-process:test");
NodeProperties node2 = new NodeProperties("0.0.4", "invalid:test");
monitorProperties.setNodes(Set.of(node1, node2));
// Initialize publisher internals with first transaction
cryptoServiceStub.addTransactions(Mono.just(response(OK)));
PublishRequest publishRequest = request().build();
publishRequest.getTransaction().setNodeAccountIds(node1.getAccountIds());
transactionPublisher.publish(publishRequest).as(StepVerifier::create).expectNextCount(1L).expectComplete().verify(Duration.ofSeconds(1L));
// Validate one of the nodes as down manually
assertThat(transactionPublisher.validateNode(node2)).isFalse();
cryptoServiceStub.addTransactions(Mono.just(response(OK)));
transactionPublisher.publish(request().build()).as(StepVerifier::create).expectNextCount(1L).expectComplete().verify(Duration.ofSeconds(1L));
}
use of com.hedera.mirror.monitor.NodeProperties in project hedera-mirror-node by hashgraph.
the class TransactionPublisherTest method validationRecovers.
@Test
@Timeout(3)
void validationRecovers() {
// Initialize publisher internals with first transaction
var request = request().build();
cryptoServiceStub.addTransactions(Mono.just(response(OK)));
transactionPublisher.publish(request).as(StepVerifier::create).expectNextCount(1L).expectComplete().verify(Duration.ofSeconds(1L));
var scenario = request.getScenario();
assertThat(scenario.getCount()).isEqualTo(1);
assertThat(scenario.getErrors()).isEmpty();
// Validate node as down manually
NodeProperties nodeProperties = monitorProperties.getNodes().iterator().next();
cryptoServiceStub.addQueries(Mono.just(receipt(ACCOUNT_DELETED)));
cryptoServiceStub.addTransactions(Mono.just(response(OK)));
assertThat(transactionPublisher.validateNode(nodeProperties)).isFalse();
request = request().build();
transactionPublisher.publish(request).as(StepVerifier::create).expectErrorSatisfies(t -> assertThat(t).isInstanceOf(PublishException.class).hasMessageContaining("No valid nodes available").hasCauseInstanceOf(IllegalArgumentException.class)).verify(Duration.ofSeconds(1L));
scenario = request.getScenario();
assertThat(scenario.getCount()).isZero();
assertThat(scenario.getErrors()).containsOnly(Map.entry(IllegalArgumentException.class.getSimpleName(), 1));
// Node recovers
cryptoServiceStub.addQueries(Mono.just(receipt(SUCCESS)));
cryptoServiceStub.addTransactions(Mono.just(response(OK)));
assertThat(transactionPublisher.validateNode(nodeProperties)).isTrue();
request = request().build();
cryptoServiceStub.addTransactions(Mono.just(response(OK)));
transactionPublisher.publish(request).as(StepVerifier::create).expectNextCount(1L).expectComplete().verify(Duration.ofSeconds(1L));
scenario = request.getScenario();
assertThat(scenario.getCount()).isEqualTo(1);
assertThat(scenario.getErrors()).isEmpty();
}
Aggregations