diff --git a/build.gradle b/build.gradle index 00e4f013ae..88391a17f3 100644 --- a/build.gradle +++ b/build.gradle @@ -49,26 +49,27 @@ allprojects { project.ext.versions = [ kafka : '3.6.2', - guava : '23.0', - jackson : '2.15.2', - jersey : '3.1.2', - jetty : '12.0.7', + guava : '33.1.0-jre', + jackson : '2.17.0', + jersey : '3.1.6', + jetty : '12.0.8', curator : '5.4.0', - dropwizard_metrics: '4.1.0', - micrometer_metrics: '1.11.1', - wiremock : '3.3.1', - spock : '2.4-M1-groovy-4.0', - groovy : '4.0.12', - avro : '1.9.1', + dropwizard_metrics: '4.2.25', + micrometer_metrics: '1.12.5', + wiremock : '3.5.2', + spock : '2.4-M4-groovy-4.0', + groovy : '4.0.21', + avro : '1.11.3', json2avro : '0.2.14', + // TODO: newest version requires subject alternative name in a certificate during host verification, current test cert does not have a one okhttp : '3.9.1', - undertow : '2.0.29.Final', - spring_web : '6.1.2', - failsafe : '2.3.1', - junit_jupiter : '5.9.1', - testcontainers : '1.18.1', - spring : '3.2.1', - assertj : '3.24.2' + undertow : '2.3.12.Final', + spring_web : '6.1.6', + failsafe : '2.4.4', + junit_jupiter : '5.10.2', + testcontainers : '1.19.8', + spring : '3.2.4', + assertj : '3.25.3' ] repositories { @@ -77,15 +78,14 @@ allprojects { dependencies { implementation group: 'org.slf4j', name: 'slf4j-api', version: '2.0.4' - implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.9' + implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.14.0' testImplementation group: 'junit', name: 'junit', version: '4.11' testImplementation group: 'com.tngtech.java', name: 'junit-dataprovider', version: '1.10.0' testImplementation group: 'pl.pragmatists', name: 'JUnitParams', version: '1.0.2' - testImplementation group: 'org.mockito', name: 'mockito-all', version: '1.9.5' + testImplementation group: 'org.mockito', name: 'mockito-core', version: '5.11.0' testImplementation group: 'org.assertj', name: 'assertj-core', version: versions.assertj - testImplementation group: 'com.jayway.awaitility', name: 'awaitility', version: '1.6.1' - testImplementation group: 'com.googlecode.catch-exception', name: 'catch-exception', version: '1.2.0' + testImplementation group: 'org.awaitility', name: 'awaitility', version: '4.2.1' annotationProcessor group: 'org.springframework.boot', name: 'spring-boot-configuration-processor', version: versions.spring } diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index dc2d859510..9f07d83fc8 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -30,19 +30,6 @@ services: - kafka_data:/var/lib/kafka/data - kafka_secrets:/etc/kafka/secrets - graphite: - image: graphiteapp/graphite-statsd:1.1.3 - ports: - - '2003-2004:2003-2004' - - '2023-2024:2023-2024' - - '8125:8125/udp' - - '8126:8126' - - '8082:80' - volumes: - - graphite_conf:/opt/graphite/conf - - graphite_data:/opt/graphite/storage - - statsd_data:/opt/statsd - frontend: build: context: ../ @@ -52,7 +39,6 @@ services: depends_on: - zk - kafka - - graphite consumers: build: @@ -61,7 +47,6 @@ services: depends_on: - zk - kafka - - graphite management: build: @@ -72,7 +57,6 @@ services: depends_on: - zk - kafka - - graphite schema-registry: image: "confluentinc/cp-schema-registry:${CONFLUENT_IMAGES_TAG}" @@ -87,9 +71,6 @@ services: - "8081:8081" volumes: - graphite_conf: - graphite_data: - statsd_data: zk_secrets: zk_data: zk_log: diff --git a/docker/latest/consumers/consumers.yaml b/docker/latest/consumers/consumers.yaml index 76af83d9b5..f64008630f 100644 --- a/docker/latest/consumers/consumers.yaml +++ b/docker/latest/consumers/consumers.yaml @@ -8,11 +8,6 @@ consumer: clusters: - datacenter: "dc" brokerList: "kafka:29092" - graphite: - host: "graphite" - metrics: - metric-registry: - graphiteReporterEnabled: true workload: consumerPerSubscription: 1 schema: diff --git a/docker/latest/frontend/frontend.yaml b/docker/latest/frontend/frontend.yaml index 2ccd0f3432..0ba33ab769 100644 --- a/docker/latest/frontend/frontend.yaml +++ b/docker/latest/frontend/frontend.yaml @@ -8,11 +8,6 @@ frontend: clusters: - datacenter: "dc" brokerList: "kafka:29092" - graphite: - host: "graphite" - metrics: - metric-registry: - graphiteReporterEnabled: true schema: cache: refreshAfterWrite: 1m diff --git a/docker/latest/management/management.yaml b/docker/latest/management/management.yaml index 0953e3660d..a678f65d33 100644 --- a/docker/latest/management/management.yaml +++ b/docker/latest/management/management.yaml @@ -17,11 +17,6 @@ kafka: connectionTimeout: 3000 bootstrapKafkaServer: kafka:29092 -graphite: - client: - enabled: true - externalMonitoringUrl: graphite:8082 - server: port: 8090 diff --git a/docs/docs/configuration/buffer-persistence.md b/docs/docs/configuration/buffer-persistence.md index a4e3b9ca66..875776f508 100644 --- a/docs/docs/configuration/buffer-persistence.md +++ b/docs/docs/configuration/buffer-persistence.md @@ -1,4 +1,4 @@ -# Publishing buffer persistence +# Publishing buffer persistence [deprecated] Hermes Frontend API has option to register callbacks triggered during different phases of message lifetime: @@ -15,7 +15,7 @@ to disk. Map structure is continuously persisted to disk, as it is stored in off When Hermes Frontend starts up it scans filesystem in search of existing persisted map. If found, it is read and any persisted events are sent to Message Store. This way recovering after crash is fully automatic. If Hermes process or -server crashes, nothing is lost. +server crashes, events that were flushed to disk are recovered. There is additional protection against flooding subscribers with outdated events. When reading events from persisted storage, Hermes filters out messages older than N hours, where N is a system parameter and is set to 3 days by default. diff --git a/docs/docs/configuration/consumers-tuning.md b/docs/docs/configuration/consumers-tuning.md index f4433b819f..904df5eede 100644 --- a/docs/docs/configuration/consumers-tuning.md +++ b/docs/docs/configuration/consumers-tuning.md @@ -2,18 +2,18 @@ ## HTTP Sender -Option | Description | Default value ----------------------------------------------------- | ----------------------------------------------------------- | ------------- -consumer.http-client.serial.http1.threadPoolSize | size of thread pool for sender threads (global) | 30 -consumer.http-client.serial.http1.maxConnectionsPerDestination | max connections per remote host | 100 +| Option | Description | Default value | +|----------------------------------------------------------------|-------------------------------------------------|---------------| +| consumer.http-client.serial.http1.threadPoolSize | size of thread pool for sender threads (global) | 30 | +| consumer.http-client.serial.http1.maxConnectionsPerDestination | max connections per remote host | 100 | ## Consumers core -Option | Description | Default value ------------------------------ | ------------------------------------------------------------------------ | ------------- -consumer.commit.offset.period | interval between committing offsets to Kafka | 60s -consumer.threadPoolSize | thread pool for threads involved in consuming, 1 thread per subscription | 500 -consumer.serialConsumer.inflightSize | how many messages can be kept in send queue, per subscription | 100 +| Option | Description | Default value | +|--------------------------------------|--------------------------------------------------------------------------|---------------| +| consumer.commit.offset.period | interval between committing offsets to Kafka | 60s | +| consumer.threadPoolSize | thread pool for threads involved in consuming, 1 thread per subscription | 500 | +| consumer.serialConsumer.inflightSize | how many messages can be kept in send queue, per subscription | 100 | ## Workload constraints management @@ -26,10 +26,10 @@ subscriptions assigned to itself. These numbers can be configured: -Option | Description | Default value ---------------------------------------------------- | ----------------------------------------- | --------------------- -consumer.workload.consumersPerSubscription | Number of consumers to which the subscription will be assigned. If this value is greater than the number of available consumers, Hermes will assign the subscription to all available consumers. | 2 -consumer.workload.maxSubscriptionsPerConsumer | The maximum number of subscriptions assigned to a single consumer. If all consumers have the maximum number of subscriptions assigned, a new subscription will not be activated until a new consumer is added or another subscription is unassigned. | 200 +| Option | Description | Default value | +|-----------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------| +| consumer.workload.consumersPerSubscription | Number of consumers to which the subscription will be assigned. If this value is greater than the number of available consumers, Hermes will assign the subscription to all available consumers. | 2 | +| consumer.workload.maxSubscriptionsPerConsumer | The maximum number of subscriptions assigned to a single consumer. If all consumers have the maximum number of subscriptions assigned, a new subscription will not be activated until a new consumer is added or another subscription is unassigned. | 200 | Additionally, Hermes allows to configure the property `consumer.workload.consumersPerSubscription` for specific topics or subscriptions in the runtime via REST API. diff --git a/docs/docs/overview/architecture.md b/docs/docs/overview/architecture.md index 7726745068..6d647e64d2 100644 --- a/docs/docs/overview/architecture.md +++ b/docs/docs/overview/architecture.md @@ -16,7 +16,7 @@ Hermes integrates with multiple systems, each having different role. * **Message Store** - stores and routes messages, current implementation: Kafka * **Metadata Store** - shared metadata storage for all Hermes modules, current implementation: Zookeeper -* **Metrics Store** *[optional]* - stores metrics gathered by Hermes, current implementation: Graphite +* **Metrics Store** *[optional]* - stores metrics gathered by Hermes, currently Hermes exposes metrics in Prometheus format * **Tracking Store** *[optional]* - stores tracking (message trace) information, current implementation: ElasticSearch ## Message flow diff --git a/docs/docs/quickstart.md b/docs/docs/quickstart.md index c31db5a01a..3ad00ea47b 100644 --- a/docs/docs/quickstart.md +++ b/docs/docs/quickstart.md @@ -56,7 +56,7 @@ image: allegro/hermes-management:hermes-[specific version tag] ## Development The default `docker-compose` setup will start all hermes modules (consumers, frontend, management), together -with its dependencies (Kafka, ZooKeeper, Graphite, Schema Registry). To run a specific module with gradle/IntelliJ, +with its dependencies (Kafka, ZooKeeper, Schema Registry). To run a specific module with gradle/IntelliJ, just comment out the module in `services` section of the `docker-compose.yml` file, and start the java process locally: `./gradlew -p hermes-frontend run` @@ -175,7 +175,6 @@ management: depends_on: - zk - kafka - - graphite [...] ``` diff --git a/docs/docs/user/java-client.md b/docs/docs/user/java-client.md index 57e78b766b..942c9675a7 100644 --- a/docs/docs/user/java-client.md +++ b/docs/docs/user/java-client.md @@ -19,7 +19,7 @@ At the moment there are four implementations of `HermesSender`: for asynchronous transmission * **WebClientHermesSender** - for services using [Spring WebFlux](https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html); uses [WebClient](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/reactive/function/client/WebClient.html) -* **JerseyHermesSender** - recommended for services using [Jersey]() +* **JerseyHermesSender** - recommended for services using [Jersey]() * **OkHttpHermesSender** - supports both HTTP/1.1 and HTTP/2 protocols, uses [OkHttp3 client](http://square.github.io/okhttp/) diff --git a/docs/docs/user/publishing.md b/docs/docs/user/publishing.md index 034d2ce623..4889a49fcb 100644 --- a/docs/docs/user/publishing.md +++ b/docs/docs/user/publishing.md @@ -134,22 +134,21 @@ Failure statuses: Each topic can define level of acknowledgement (ACK): * leader ACK - only one Kafka node (leader) needs to acknowledge reception of message -* all ACK - all nodes that hold copy of message need to acknowledge reception of message +* all ACK - at least [min.insync.replicas](https://kafka.apache.org/documentation/#brokerconfigs_min.insync.replicas) nodes must acknowledge reception of message -For most of the topic leader ACK is enough. This guarantees roughly 99.999..% reception rate. Only in rare cases, during -Kafka cluster rebalancing or nodes outage Kafka might confirm that message was received, while it was not saved and it -will be lost. +ACK configuration has the following consequences: -What does it mean in practice? Numbers differ per case and they are affected by multiple factors like frequency of -rebalancing taking place on Kafka clusters, Kafka version etc. In our production environment using ACK leader means we falsely -believe message was received by Kafka once per 20 million events. This is a very rough estimate that should show you -the scale, if you need numbers to base your decision on - please conduct own measurements. +- with `ACK leader` message writes are replicated asynchronously, thus the acknowledgment latency will be low. However, message write may be lost +when there is a topic leadership change - e.g. due to rebalance or broker restart. +- with `ACK all` messages writes are synchronously replicated to replicas. Write acknowledgement latency will be much higher than with leader ACK, +it will also have higher variance due to tail latency. However, messages will be persisted as long as the whole replica set does not go down simultaneously. -If you need 100% guarantee that message was saved, force all replicas to send ACK. The downside of this is much longer -response times, they tend to vary a lot as well. Thanks to Hermes buffering (described in paragraphs below), we are able -to guarantee some sane response times to our clients even in *ACK all* mode. +Publishers are advised to select topic ACK level based on their latency and durability requirements. -## Buffering +Hermes also provides a feature called Buffering (described in paragraphs below) which provides consistent write latency +despite long Kafka response times. Note that, however, this mode may decrease message durability for `ACK all` setting. + +## Buffering [deprecated] Hermes administrator can set maximum time, for which Hermes will wait for Kafka acknowledgment. By default, it is set to 65ms. After that time, **202** response is sent to client. Event is kept in Kafka producer buffer and it's delivery will @@ -161,7 +160,7 @@ Kafka is back online. ### Buffer persistence -By default events are buffered in memory only. This raises the question about what happens in case of Hermes node failure +By default, events are buffered in memory only. This raises the question about what happens in case of Hermes node failure (or force kill of process). Hermes Frontend API exposes callbacks that can be used to implement persistence model of buffered events. @@ -169,6 +168,46 @@ Default implementation uses [OpenHFT ChronicleMap](https://github.com/OpenHFT/Ch to disk. Map structure is continuously persisted to disk, as it is stored in offheap memory as [memory mapped file](https://en.wikipedia.org/wiki/Memory-mapped_file). +Using buffering with ACK all setting means that durability of events may be lowered when **202** status code is received. If Hermes instance +is killed before message is spilled to disk or the data on disk becomes corrupted, the message is gone. Thus `ACK all` with **202** status code +is similar to `ACK leader` because a single node failure could cause the message be lost. + +### Deprecation notice +The buffering mechanism in Hermes is considered deprecated and is set to be removed in the future. + +## Remote DC fallback + +Hermes supports a remote datacenter fallback mechanism for [multi datacenter deployments](https://hermes-pubsub.readthedocs.io/en/latest/configuration/kafka-and-zookeeper/#multiple-kafka-and-zookeeper-clusters). + +Fallback is configured on per topic basis, using a `fallbackToRemoteDatacenterEnabled` property: + +```http request +PUT /topics/my.group.my-topic + +{ + "fallbackToRemoteDatacenterEnabled": true, +} +``` + +Using this setting automatically disables buffering mechanism for a topic. + +When using this setting for a topic, Hermes will try to send a message to a local datacenter Kafka first and will fall back to remote datacenter Kafka +if the local send fails. + +Hermes also provides a speculative fallback mechanism which will send messages to remote Kafka if the local Kafka is not responding in a timely manner. +Speculative send is performed after `frontend.kafka.fail-fast-producer.speculativeSendDelay` elapses. + +When using remote DC fallback, Hermes attempts to send a message to Kafka for the duration of `frontend.handlers.maxPublishRequestDuration` property. If after +`maxPublishRequestDuration` Hermes has not received an acknowledgment from Kafka, it will respond with **500** status code to the client. + +Table below summarizes remote fallback configuration options: + +| Option | Scope | Default value | +|--------------------------------------------------------|--------|---------------| +| fallbackToRemoteDatacenterEnabled | topic | false | +| frontend.kafka.fail-fast-producer.speculativeSendDelay | global | 250ms | +| frontend.handlers.maxPublishRequestDuration | global | 500ms | + ## Partition assignment `Partition-Key` header can be used by publishers to specify Kafka `key` which will be used for partition assignment for a message. This will ensure that all messages with given `Partition-Key` will be sent to the same Kafka partition. diff --git a/hermes-api/build.gradle b/hermes-api/build.gradle index c6554f612b..54c06d0400 100644 --- a/hermes-api/build.gradle +++ b/hermes-api/build.gradle @@ -4,19 +4,19 @@ plugins { } dependencies { - api group: 'org.hibernate.validator', name: 'hibernate-validator', version: '8.0.0.Final' + api group: 'org.hibernate.validator', name: 'hibernate-validator', version: '8.0.1.Final' api group: 'jakarta.ws.rs', name: 'jakarta.ws.rs-api', version: '3.1.0' implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: versions.jackson api group: 'com.fasterxml.jackson.jakarta.rs', name: 'jackson-jakarta-rs-json-provider', version: versions.jackson api group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: versions.jackson implementation group: 'com.google.guava', name: 'guava', version: versions.guava - api group: 'com.damnhandy', name: 'handy-uri-templates', version: '2.0.2' + api group: 'com.damnhandy', name: 'handy-uri-templates', version: '2.1.8' api group: 'jakarta.xml.bind', name: 'jakarta.xml.bind-api', version: '4.0.0' - implementation group: 'com.sun.xml.bind', name: 'jaxb-core', version: '4.0.3' - implementation group: 'com.sun.xml.bind', name: 'jaxb-impl', version: '4.0.3' - implementation group: 'jakarta.annotation', name: 'jakarta.annotation-api', version: '2.1.1' + implementation group: 'com.sun.xml.bind', name: 'jaxb-core', version: '4.0.5' + implementation group: 'com.sun.xml.bind', name: 'jaxb-impl', version: '4.0.5' + implementation group: 'jakarta.annotation', name: 'jakarta.annotation-api', version: '3.0.0' testImplementation group: 'org.spockframework', name: 'spock-core', version: versions.spock diff --git a/hermes-api/src/main/java/pl/allegro/tech/hermes/api/Subscription.java b/hermes-api/src/main/java/pl/allegro/tech/hermes/api/Subscription.java index 3a8c673590..14849437df 100644 --- a/hermes-api/src/main/java/pl/allegro/tech/hermes/api/Subscription.java +++ b/hermes-api/src/main/java/pl/allegro/tech/hermes/api/Subscription.java @@ -52,6 +52,8 @@ public class Subscription implements Anonymizable { private boolean trackingEnabled = false; private TrackingMode trackingMode = TrackingMode.TRACKING_OFF; private boolean http2Enabled = false; + private boolean profilingEnabled = false; + private long profilingThresholdMs = 0; @Valid @NotNull private OwnerId owner; @@ -94,6 +96,8 @@ private Subscription(TopicName topicName, EndpointAddressResolverMetadata endpointAddressResolverMetadata, SubscriptionOAuthPolicy oAuthPolicy, boolean http2Enabled, + boolean profilingEnabled, + long profilingThresholdMs, boolean subscriptionIdentityHeadersEnabled, boolean autoDeleteWithTopicEnabled) { this.topicName = topicName; @@ -112,6 +116,8 @@ private Subscription(TopicName topicName, this.filters = filters; this.mode = mode; this.http2Enabled = http2Enabled; + this.profilingEnabled = profilingEnabled; + this.profilingThresholdMs = profilingThresholdMs; this.subscriptionName = new SubscriptionName(name, topicName); this.headers = headers; this.endpointAddressResolverMetadata = endpointAddressResolverMetadata; @@ -137,11 +143,13 @@ public static Subscription createSerialSubscription(TopicName topicName, EndpointAddressResolverMetadata endpointAddressResolverMetadata, SubscriptionOAuthPolicy oAuthPolicy, boolean http2Enabled, + boolean profilingEnabled, + long profilingThresholdMs, boolean subscriptionIdentityHeadersEnabled, boolean autoDeleteWithTopicEnabled) { return new Subscription(topicName, name, endpoint, state, description, subscriptionPolicy, trackingEnabled, trackingMode, owner, monitoringDetails, contentType, DeliveryType.SERIAL, filters, mode, headers, - endpointAddressResolverMetadata, oAuthPolicy, http2Enabled, subscriptionIdentityHeadersEnabled, autoDeleteWithTopicEnabled); + endpointAddressResolverMetadata, oAuthPolicy, http2Enabled, profilingEnabled, profilingThresholdMs, subscriptionIdentityHeadersEnabled, autoDeleteWithTopicEnabled); } public static Subscription createBatchSubscription(TopicName topicName, @@ -164,7 +172,7 @@ public static Subscription createBatchSubscription(TopicName topicName, boolean autoDeleteWithTopicEnabled) { return new Subscription(topicName, name, endpoint, state, description, subscriptionPolicy, trackingEnabled, trackingMode, owner, monitoringDetails, contentType, DeliveryType.BATCH, filters, SubscriptionMode.ANYCAST, headers, - endpointAddressResolverMetadata, oAuthPolicy, http2Enabled, subscriptionIdentityHeadersEnabled, autoDeleteWithTopicEnabled); + endpointAddressResolverMetadata, oAuthPolicy, http2Enabled, false, 0, subscriptionIdentityHeadersEnabled, autoDeleteWithTopicEnabled); } @JsonCreator @@ -187,6 +195,8 @@ public static Subscription create( @JsonProperty("endpointAddressResolverMetadata") EndpointAddressResolverMetadata endpointAddressResolverMetadata, @JsonProperty("oAuthPolicy") SubscriptionOAuthPolicy oAuthPolicy, @JsonProperty("http2Enabled") boolean http2Enabled, + @JsonProperty("profilingEnabled") boolean profilingEnabled, + @JsonProperty("profilingThresholdMs") long profilingThresholdMs, @JsonProperty("subscriptionIdentityHeadersEnabled") boolean subscriptionIdentityHeadersEnabled, @JsonProperty("autoDeleteWithTopicEnabled") boolean autoDeleteWithTopicEnabled) { @@ -219,6 +229,8 @@ public static Subscription create( endpointAddressResolverMetadata == null ? EndpointAddressResolverMetadata.empty() : endpointAddressResolverMetadata, oAuthPolicy, http2Enabled, + profilingEnabled, + profilingThresholdMs, subscriptionIdentityHeadersEnabled, autoDeleteWithTopicEnabled ); @@ -257,6 +269,8 @@ public boolean equals(Object obj) { && Objects.equals(this.headers, other.headers) && Objects.equals(this.endpointAddressResolverMetadata, other.endpointAddressResolverMetadata) && Objects.equals(this.http2Enabled, other.http2Enabled) + && Objects.equals(this.profilingEnabled, other.profilingEnabled) + && Objects.equals(this.profilingThresholdMs, other.profilingThresholdMs) && Objects.equals(this.oAuthPolicy, other.oAuthPolicy) && Objects.equals(this.subscriptionIdentityHeadersEnabled, other.subscriptionIdentityHeadersEnabled) && Objects.equals(this.autoDeleteWithTopicEnabled, other.autoDeleteWithTopicEnabled); @@ -391,6 +405,14 @@ public boolean isHttp2Enabled() { return http2Enabled; } + public boolean isProfilingEnabled() { + return profilingEnabled; + } + + public long getProfilingThresholdMs() { + return profilingThresholdMs; + } + public boolean isSubscriptionIdentityHeadersEnabled() { return subscriptionIdentityHeadersEnabled; } @@ -437,6 +459,8 @@ public Subscription anonymize() { endpointAddressResolverMetadata, oAuthPolicy != null ? oAuthPolicy.anonymize() : null, http2Enabled, + profilingEnabled, + profilingThresholdMs, subscriptionIdentityHeadersEnabled, autoDeleteWithTopicEnabled ); diff --git a/hermes-benchmark/build.gradle b/hermes-benchmark/build.gradle index abd76e7967..6262b38a8a 100644 --- a/hermes-benchmark/build.gradle +++ b/hermes-benchmark/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'me.champeau.jmh' version '0.6.8' + id 'me.champeau.jmh' version '0.7.2' } configurations { @@ -26,10 +26,9 @@ jmh { } dependencies { - jmh group: 'org.openjdk.jmh', name: 'jmh-core', version: '1.12' - jmh group: 'org.openjdk.jmh', name: 'jmh-generator-annprocess', version: '1.12' - jmh group: 'org.apache.httpcomponents', name: 'httpasyncclient', version: '4.1.1' - jmh group: 'org.spf4j', name: 'spf4j-jmh', version: '8.0.3' + jmh group: 'org.openjdk.jmh', name: 'jmh-core', version: '1.37' + jmh group: 'org.openjdk.jmh', name: 'jmh-generator-annprocess', version: '1.37' + jmh group: 'org.apache.httpcomponents', name: 'httpasyncclient', version: '4.1.5' jmh project(':hermes-frontend') jmh project(':hermes-test-helper') jmh project(':hermes-common') diff --git a/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/HermesPublisher.java b/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/HermesPublisher.java index 610eafea81..65d758873d 100644 --- a/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/HermesPublisher.java +++ b/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/HermesPublisher.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.benchmark.environment; -import com.codahale.metrics.MetricRegistry; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.config.CookieSpecs; @@ -28,14 +27,12 @@ public class HermesPublisher { private static final Logger logger = LoggerFactory.getLogger(HermesPublisher.class); private final CloseableHttpAsyncClient httpClient; - private final MetricRegistry metricRegistry; private final URI targetUrl; private final HttpEntity body; - public HermesPublisher(int maxConnectionsPerRoute, String targetUrl, String body, MetricRegistry metricRegistry) + public HermesPublisher(int maxConnectionsPerRoute, String targetUrl, String body) throws IOReactorException, UnsupportedEncodingException { this.targetUrl = URI.create(targetUrl); - this.metricRegistry = metricRegistry; RequestConfig requestConfig = RequestConfig.custom() .setCookieSpec(CookieSpecs.IGNORE_COOKIES) @@ -71,9 +68,7 @@ public int publish() { try { Future future = httpClient.execute(httpPost, null); response = future.get().getStatusLine().getStatusCode(); - metricRegistry.counter("response." + response).inc(); } catch (RuntimeException | InterruptedException | ExecutionException exception) { - metricRegistry.counter("client.exceptions").inc(); logger.error("Client exception", exception); } return response; diff --git a/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/HermesServerEnvironment.java b/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/HermesServerEnvironment.java index 52aece4222..2f987a610f 100644 --- a/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/HermesServerEnvironment.java +++ b/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/HermesServerEnvironment.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.benchmark.environment; -import com.codahale.metrics.MetricRegistry; import org.apache.commons.io.IOUtils; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Scope; @@ -23,7 +22,6 @@ public class HermesServerEnvironment { public static final String BENCHMARK_TOPIC = "bench.topic"; private HermesPublisher publisher; - private MetricRegistry metricRegistry; private HermesServer hermesServer; @@ -39,10 +37,9 @@ public void setupEnvironment() throws Exception { @Setup(Level.Trial) public void setupPublisher() throws Exception { - metricRegistry = new MetricRegistry(); String messageBody = loadMessageResource("completeMessage"); - publisher = new HermesPublisher(MAX_CONNECTIONS_PER_ROUTE, "http://localhost:8080/topics/" + BENCHMARK_TOPIC, messageBody, metricRegistry); + publisher = new HermesPublisher(MAX_CONNECTIONS_PER_ROUTE, "http://localhost:8080/topics/" + BENCHMARK_TOPIC, messageBody); } @TearDown(Level.Trial) @@ -52,7 +49,6 @@ public void shutdownServers() throws Exception { @TearDown(Level.Trial) public void shutdownPublisherAndReportMetrics() throws Exception { - reportMetrics(); publisher.stop(); } @@ -65,7 +61,4 @@ public static String loadMessageResource(String name) throws IOException { .getResourceAsStream(String.format("/message/%s.json", name)))); } - private void reportMetrics() { - metricRegistry.getCounters().forEach((key, value) -> logger.info(key + ": " + value.getCount())); - } } diff --git a/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/HermesServerFactory.java b/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/HermesServerFactory.java index c47b324f7b..47c5dbca6f 100644 --- a/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/HermesServerFactory.java +++ b/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/HermesServerFactory.java @@ -1,12 +1,10 @@ package pl.allegro.tech.hermes.benchmark.environment; -import com.codahale.metrics.MetricRegistry; import com.fasterxml.jackson.databind.ObjectMapper; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import io.undertow.server.HttpHandler; import pl.allegro.tech.hermes.api.Topic; import pl.allegro.tech.hermes.common.message.wrapper.AvroMessageContentWrapper; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; import pl.allegro.tech.hermes.frontend.cache.topic.TopicsCache; import pl.allegro.tech.hermes.frontend.config.HTTPHeadersProperties; @@ -28,7 +26,6 @@ import pl.allegro.tech.hermes.frontend.readiness.HealthCheckService; import pl.allegro.tech.hermes.frontend.server.HermesServer; import pl.allegro.tech.hermes.frontend.validator.MessageValidators; -import pl.allegro.tech.hermes.metrics.PathsCompiler; import pl.allegro.tech.hermes.schema.DirectCompiledSchemaRepository; import pl.allegro.tech.hermes.schema.DirectSchemaVersionsRepository; import pl.allegro.tech.hermes.schema.RawSchemaClient; @@ -52,8 +49,7 @@ class HermesServerFactory { static HermesServer provideHermesServer() throws IOException { ThroughputLimiter throughputLimiter = (exampleTopic, throughput) -> quotaConfirmed(); - HermesMetrics hermesMetrics = new HermesMetrics(new MetricRegistry(), new PathsCompiler("")); - MetricsFacade metricsFacade = new MetricsFacade(new SimpleMeterRegistry(), hermesMetrics); + MetricsFacade metricsFacade = new MetricsFacade(new SimpleMeterRegistry()); TopicsCache topicsCache = new InMemoryTopicsCache(metricsFacade, topic); BrokerMessageProducer brokerMessageProducer = new InMemoryBrokerMessageProducer(); RawSchemaClient rawSchemaClient = new InMemorySchemaClient(topic.getName(), loadMessageResource("schema"), 1, 1); diff --git a/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/InMemoryTopicsCache.java b/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/InMemoryTopicsCache.java index d673c51187..d7425b67d5 100644 --- a/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/InMemoryTopicsCache.java +++ b/hermes-benchmark/src/jmh/java/pl/allegro/tech/hermes/benchmark/environment/InMemoryTopicsCache.java @@ -1,13 +1,14 @@ package pl.allegro.tech.hermes.benchmark.environment; +import com.codahale.metrics.MetricRegistry; import pl.allegro.tech.hermes.api.Topic; import pl.allegro.tech.hermes.common.kafka.KafkaTopic; import pl.allegro.tech.hermes.common.kafka.KafkaTopicName; import pl.allegro.tech.hermes.common.kafka.KafkaTopics; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; import pl.allegro.tech.hermes.frontend.cache.topic.TopicsCache; import pl.allegro.tech.hermes.frontend.metric.CachedTopic; +import pl.allegro.tech.hermes.frontend.metric.ThroughputRegistry; import java.util.List; import java.util.Optional; @@ -17,12 +18,14 @@ class InMemoryTopicsCache implements TopicsCache { private final MetricsFacade metricsFacade; private final KafkaTopics kafkaTopics; private final Topic topic; + private final ThroughputRegistry throughputRegistry; InMemoryTopicsCache(MetricsFacade metricsFacade, Topic topic) { this.metricsFacade = metricsFacade; this.topic = topic; this.kafkaTopics = new KafkaTopics(new KafkaTopic(KafkaTopicName.valueOf(topic.getQualifiedName()), topic.getContentType())); + this.throughputRegistry = new ThroughputRegistry(metricsFacade, new MetricRegistry()); } @Override @@ -32,6 +35,7 @@ public Optional getTopic(String qualifiedTopicName) { new CachedTopic( topic, metricsFacade, + throughputRegistry, kafkaTopics ) ); diff --git a/hermes-client/build.gradle b/hermes-client/build.gradle index c8dd30dfe6..8e2fa2c039 100644 --- a/hermes-client/build.gradle +++ b/hermes-client/build.gradle @@ -3,7 +3,6 @@ plugins { } dependencies { - compileOnly group: 'io.dropwizard.metrics', name: 'metrics-core', version: versions.dropwizard_metrics compileOnly group: 'io.micrometer', name: 'micrometer-core', version: versions.micrometer_metrics compileOnly group: 'org.glassfish.jersey.core', name: 'jersey-client', version: versions.jersey compileOnly group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: versions.jersey @@ -12,15 +11,14 @@ dependencies { compileOnly group: 'com.squareup.okhttp3', name: 'okhttp', version: versions.okhttp implementation group: 'net.jodah', name: 'failsafe', version: versions.failsafe - api group: 'io.projectreactor', name: 'reactor-core', version: '3.4.25' + api group: 'io.projectreactor', name: 'reactor-core', version: '3.6.5' testImplementation group: 'org.spockframework', name: 'spock-core', version: versions.spock testImplementation group: 'org.spockframework', name: 'spock-junit4', version: versions.spock testImplementation group: 'org.wiremock', name: 'wiremock-standalone', version: versions.wiremock - testImplementation group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0' - testImplementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.5.0' + testImplementation group: 'jakarta.servlet', name: 'jakarta.servlet-api', version: '6.0.0' + testImplementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.9.0' - testImplementation group: 'io.dropwizard.metrics', name: 'metrics-core', version: versions.dropwizard_metrics testImplementation group: 'io.micrometer', name: 'micrometer-core', version: versions.micrometer_metrics testImplementation group: 'org.glassfish.jersey.core', name: 'jersey-client', version: versions.jersey testImplementation group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: versions.jersey @@ -28,6 +26,6 @@ dependencies { testImplementation group: 'org.springframework', name: 'spring-context', version: versions.spring_web testImplementation group: 'org.springframework', name: 'spring-webflux', version: versions.spring_web testImplementation group: 'com.squareup.okhttp3', name: 'okhttp', version: versions.okhttp - testImplementation group: 'io.projectreactor.netty', name: 'reactor-netty', version: '1.0.25' - testImplementation group: 'io.projectreactor', name: 'reactor-test', version: '3.4.25' + testImplementation group: 'io.projectreactor.netty', name: 'reactor-netty', version: '1.1.18' + testImplementation group: 'io.projectreactor', name: 'reactor-test', version: '3.6.5' } diff --git a/hermes-client/src/main/java/pl/allegro/tech/hermes/client/metrics/DropwizardMetricsProvider.java b/hermes-client/src/main/java/pl/allegro/tech/hermes/client/metrics/DropwizardMetricsProvider.java deleted file mode 100644 index ded184d90e..0000000000 --- a/hermes-client/src/main/java/pl/allegro/tech/hermes/client/metrics/DropwizardMetricsProvider.java +++ /dev/null @@ -1,40 +0,0 @@ -package pl.allegro.tech.hermes.client.metrics; - -import com.codahale.metrics.MetricRegistry; - -import java.util.Map; -import java.util.concurrent.TimeUnit; - -public class DropwizardMetricsProvider implements MetricsProvider { - - private final MetricRegistry metrics; - - - public DropwizardMetricsProvider(MetricRegistry metrics) { - this.metrics = metrics; - } - - @Override - public void counterIncrement(String topic, String key) { - metrics.counter(prefix + topic + "." + key).inc(); - } - - @Override - public void counterIncrement(String topic, String key, Map tags) { - counterIncrement(topic, buildCounterName(key, tags)); - } - - @Override - public void timerRecord(String topic, String key, long duration, TimeUnit unit) { - metrics.timer(prefix + topic + "." + key).update(duration, unit); - } - - @Override - public void histogramUpdate(String topic, String key, int value) { - metrics.histogram(prefix + topic + "." + key).update(value); - } - - private String buildCounterName(String key, Map tags) { - return key + "." + String.join(".", tags.values()); - } -} diff --git a/hermes-client/src/test/groovy/pl/allegro/tech/hermes/client/HermesClientMetricsTest.groovy b/hermes-client/src/test/groovy/pl/allegro/tech/hermes/client/HermesClientMetricsTest.groovy deleted file mode 100644 index c608c1c5cc..0000000000 --- a/hermes-client/src/test/groovy/pl/allegro/tech/hermes/client/HermesClientMetricsTest.groovy +++ /dev/null @@ -1,207 +0,0 @@ -package pl.allegro.tech.hermes.client - -import com.codahale.metrics.MetricRegistry -import pl.allegro.tech.hermes.client.metrics.DropwizardMetricsProvider -import pl.allegro.tech.hermes.client.metrics.MetricsProvider -import spock.lang.Specification - -import java.time.Duration -import java.time.temporal.ChronoUnit -import java.util.concurrent.CompletableFuture - -import static java.util.concurrent.CompletableFuture.completedFuture -import static pl.allegro.tech.hermes.client.HermesClientBuilder.hermesClient - -class HermesClientMetricsTest extends Specification { - - private MetricRegistry metrics = new MetricRegistry() - private MetricsProvider metricsProvider = new DropwizardMetricsProvider(metrics) - - def "should measure publish latency"() { - given: - HermesClient client = hermesClient(delayedHermesSender(Duration.ofMillis(100))) - .withRetrySleep(0) - .withMetrics(metricsProvider).build() - - when: - client.publish("com.group.topic", "123").join() - - then: - metrics.counter("hermes-client.com_group.topic.status.201").count == 1 - metrics.timer("hermes-client.com_group.topic.latency").getSnapshot().getMax() >= Duration.ofMillis(100).get(ChronoUnit.NANOS) - } - - def "should close timer on exceptional completion and log failure metric"() { - given: - HermesClient client = hermesClient({uri, msg -> failingFuture(new RuntimeException())}) - .withRetrySleep(0) - .withRetries(3) - .withMetrics(metricsProvider).build() - - when: - silence({ client.publish("com.group.topic", "123").join() }) - - then: - metrics.counter("hermes-client.com_group.topic.failure").count == 4 - metrics.timers.containsKey("hermes-client.com_group.topic.latency") - - metrics.counter("hermes-client.com_group.topic.publish.failure").count == 4 - metrics.counter("hermes-client.com_group.topic.publish.finally.failure").count == 1 - metrics.counter("hermes-client.com_group.topic.publish.retry.failure").count == 3 - } - - def "should update max retries exceeded metric"() { - given: - HermesClient client = hermesClient({uri, msg -> failingFuture(new RuntimeException())}) - .withRetrySleep(0) - .withRetries(3) - .withMetrics(metricsProvider).build() - - when: - silence({ client.publish("com.group.topic", "123").join() }) - - then: - metrics.counter("hermes-client.com_group.topic.failure").count == 4 - metrics.counter("hermes-client.com_group.topic.retries.count").count == 3 - metrics.counter("hermes-client.com_group.topic.retries.exhausted").count == 1 - metrics.counter("hermes-client.com_group.topic.retries.success").count == 0 - metrics.histogram("hermes-client.com_group.topic.retries.attempts").getSnapshot().size() == 0 - metrics.timers.containsKey("hermes-client.com_group.topic.latency") - - metrics.counter("hermes-client.com_group.topic.publish.finally.success").count == 0 - metrics.counter("hermes-client.com_group.topic.publish.finally.failure").count == 1 - metrics.counter("hermes-client.com_group.topic.publish.failure").count == 4 - metrics.counter("hermes-client.com_group.topic.publish.attempt").count == 1 - metrics.counter("hermes-client.com_group.topic.publish.retry.success").count == 0 - metrics.counter("hermes-client.com_group.topic.publish.retry.failure").count == 3 - metrics.counter("hermes-client.com_group.topic.publish.retry.attempt").count == 1 - } - - def "should update retries metrics"() { - given: - HermesClient client1 = hermesClient(failingHermesSender(2)) - .withRetrySleep(0) - .withRetries(4) - .withMetrics(metricsProvider).build() - - HermesClient client2 = hermesClient(failingHermesSender(5)) - .withRetrySleep(0) - .withRetries(6) - .withMetrics(metricsProvider).build() - - HermesClient client3 = hermesClient(failingHermesSender(3)) - .withRetrySleep(0) - .withRetries(2) - .withMetrics(metricsProvider).build() - - when: - silence({ client1.publish("com.group.topic", "123").join() }) - silence({ client2.publish("com.group.topic", "456").join() }) - silence({ client3.publish("com.group.topic", "789").join() }) - - then: - metrics.counter("hermes-client.com_group.topic.failure").count == 10 - metrics.counter("hermes-client.com_group.topic.retries.exhausted").count == 1 - metrics.counter("hermes-client.com_group.topic.retries.success").count == 2 - metrics.counter("hermes-client.com_group.topic.retries.count").count == 9 - metrics.histogram("hermes-client.com_group.topic.retries.attempts").getSnapshot().getMin() == 2 - metrics.histogram("hermes-client.com_group.topic.retries.attempts").getSnapshot().getMax() == 5 - metrics.timers.containsKey("hermes-client.com_group.topic.latency") - - metrics.counter("hermes-client.com_group.topic.publish.finally.success").count == 2 - metrics.counter("hermes-client.com_group.topic.publish.finally.failure").count == 1 - metrics.counter("hermes-client.com_group.topic.publish.failure").count == 10 - metrics.counter("hermes-client.com_group.topic.publish.attempt").count == 3 - metrics.counter("hermes-client.com_group.topic.publish.retry.success").count == 2 - metrics.counter("hermes-client.com_group.topic.publish.retry.failure").count == 9 - metrics.counter("hermes-client.com_group.topic.publish.retry.attempt").count == 3 - } - - def "should update failure metrics when there is an application-level error"() { - given: - HermesClient client1 = hermesClient(badRequestHermesSender()) - .withRetrySleep(0) - .withRetries(4) - .withMetrics(metricsProvider).build() - - HermesClient client2 = hermesClient(badRequestHermesSender()) - .withRetrySleep(0) - .withRetries(6) - .withMetrics(metricsProvider).build() - - HermesClient client3 = hermesClient(badRequestHermesSender()) - .withRetrySleep(0) - .withRetries(2) - .withMetrics(metricsProvider).build() - - when: - silence({ client1.publish("com.group.topic", "123").join() }) - silence({ client2.publish("com.group.topic", "456").join() }) - silence({ client3.publish("com.group.topic", "789").join() }) - - then: - metrics.counter("hermes-client.com_group.topic.publish.finally.success").count == 0 - metrics.counter("hermes-client.com_group.topic.publish.finally.failure").count == 3 - metrics.counter("hermes-client.com_group.topic.publish.failure").count == 3 - metrics.counter("hermes-client.com_group.topic.publish.attempt").count == 3 - metrics.counter("hermes-client.com_group.topic.publish.retry.success").count == 0 - metrics.counter("hermes-client.com_group.topic.publish.retry.failure").count == 0 - metrics.counter("hermes-client.com_group.topic.publish.retry.attempt").count == 0 - } - - private CompletableFuture successFuture(HermesMessage message) { - return completedFuture(HermesResponseBuilder.hermesResponse(message).withHttpStatus(201).build()) - } - - private CompletableFuture badRequestFuture(HermesMessage message) { - return completedFuture(HermesResponseBuilder.hermesResponse(message).withHttpStatus(400).build()) - } - - private CompletableFuture failingFuture(Throwable throwable) { - CompletableFuture future = new CompletableFuture<>() - future.completeExceptionally(throwable) - return future - } - - private HermesSender failingHermesSender(int errorNo) { - new HermesSender() { - int i = 0 - @Override - CompletableFuture send(URI uri, HermesMessage message) { - i++ - if (i <= errorNo) { - return failingFuture(new RuntimeException()) - } - return successFuture(message) - } - } - } - - private HermesSender delayedHermesSender(Duration sendLatencyMs) { - new HermesSender() { - @Override - CompletableFuture send(URI uri, HermesMessage message) { - Thread.sleep(sendLatencyMs.toMillis()) - return successFuture(message) - } - } - } - - private HermesSender badRequestHermesSender() { - new HermesSender() { - @Override - CompletableFuture send(URI uri, HermesMessage message) { - return badRequestFuture(message) - } - } - } - - private void silence(Runnable runnable) { - try { - runnable.run() - } catch (Exception ex) { - // do nothing - } - } - -} diff --git a/hermes-client/src/test/groovy/pl/allegro/tech/hermes/client/HermesClientMicrometerTaggedMetricsTest.groovy b/hermes-client/src/test/groovy/pl/allegro/tech/hermes/client/HermesClientMicrometerTaggedMetricsTest.groovy index d7175066ec..05b760eea9 100644 --- a/hermes-client/src/test/groovy/pl/allegro/tech/hermes/client/HermesClientMicrometerTaggedMetricsTest.groovy +++ b/hermes-client/src/test/groovy/pl/allegro/tech/hermes/client/HermesClientMicrometerTaggedMetricsTest.groovy @@ -7,7 +7,6 @@ import pl.allegro.tech.hermes.client.metrics.MicrometerTaggedMetricsProvider import spock.lang.Specification import java.time.Duration -import java.time.temporal.ChronoUnit import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit @@ -31,8 +30,8 @@ class HermesClientMicrometerTaggedMetricsTest extends Specification { then: metrics.counter("hermes-client.status", "code", String.valueOf(201), "topic", "com_group.topic").count() == 1 def timer = metrics.timer("hermes-client.latency", "topic", "com_group.topic") - timer.totalTime(TimeUnit.NANOSECONDS) >= Duration.ofMillis(100).get(ChronoUnit.NANOS) - timer.totalTime(TimeUnit.NANOSECONDS) < Duration.ofMillis(300).get(ChronoUnit.NANOS) + timer.totalTime(TimeUnit.NANOSECONDS) >= Duration.ofMillis(100).toNanos() + timer.totalTime(TimeUnit.NANOSECONDS) < Duration.ofMillis(1000).toNanos() } def "should close timer on exceptional completion and log failure metric"() { diff --git a/hermes-client/src/test/groovy/pl/allegro/tech/hermes/client/ReactiveHermesClientMetricsTest.groovy b/hermes-client/src/test/groovy/pl/allegro/tech/hermes/client/ReactiveHermesClientMetricsTest.groovy deleted file mode 100644 index c1993857dd..0000000000 --- a/hermes-client/src/test/groovy/pl/allegro/tech/hermes/client/ReactiveHermesClientMetricsTest.groovy +++ /dev/null @@ -1,205 +0,0 @@ -package pl.allegro.tech.hermes.client - -import com.codahale.metrics.MetricRegistry -import pl.allegro.tech.hermes.client.metrics.DropwizardMetricsProvider -import pl.allegro.tech.hermes.client.metrics.MetricsProvider -import reactor.core.publisher.Mono -import spock.lang.Specification - -import java.time.Duration -import java.time.temporal.ChronoUnit - -import static pl.allegro.tech.hermes.client.ReactiveHermesClientBuilder.hermesClient - -class ReactiveHermesClientMetricsTest extends Specification { - - private MetricRegistry metrics = new MetricRegistry() - private MetricsProvider metricsProvider = new DropwizardMetricsProvider(metrics) - - def "should measure publish latency"() { - given: - ReactiveHermesClient client = hermesClient(delayedHermesSender(Duration.ofMillis(100))) - .withRetrySleep(0) - .withMetrics(metricsProvider).build() - - when: - client.publish("com.group.topic", "123").block() - - then: - metrics.counter("hermes-client.com_group.topic.status.201").count == 1 - metrics.timer("hermes-client.com_group.topic.latency").getSnapshot().getMax() >= Duration.ofMillis(100).get(ChronoUnit.NANOS) - metrics.timer("hermes-client.com_group.topic.latency").getSnapshot().getMax() < Duration.ofMillis(300).get(ChronoUnit.NANOS) - } - - def "should close timer on exceptional completion and log failure metric"() { - given: - ReactiveHermesClient client = hermesClient({uri, msg -> failingMono(new RuntimeException())}) - .withRetrySleep(0) - .withRetries(3) - .withMetrics(metricsProvider).build() - - when: - silence({ client.publish("com.group.topic", "123").block() }) - - then: - metrics.counter("hermes-client.com_group.topic.failure").count == 4 - metrics.timers.containsKey("hermes-client.com_group.topic.latency") - - metrics.counter("hermes-client.com_group.topic.publish.failure").count == 4 - metrics.counter("hermes-client.com_group.topic.publish.finally.failure").count == 1 - metrics.counter("hermes-client.com_group.topic.publish.retry.failure").count == 3 - } - - def "should update max retries exceeded metric"() { - given: - ReactiveHermesClient client = hermesClient({uri, msg -> failingMono(new RuntimeException())}) - .withRetrySleep(0) - .withRetries(3) - .withMetrics(metricsProvider).build() - - when: - silence({ client.publish("com.group.topic", "123").block() }) - - then: - metrics.counter("hermes-client.com_group.topic.failure").count == 4 - metrics.counter("hermes-client.com_group.topic.retries.count").count == 3 - metrics.counter("hermes-client.com_group.topic.retries.exhausted").count == 1 - metrics.counter("hermes-client.com_group.topic.retries.success").count == 0 - metrics.histogram("hermes-client.com_group.topic.retries.attempts").getSnapshot().size() == 0 - metrics.timers.containsKey("hermes-client.com_group.topic.latency") - - metrics.counter("hermes-client.com_group.topic.publish.finally.success").count == 0 - metrics.counter("hermes-client.com_group.topic.publish.finally.failure").count == 1 - metrics.counter("hermes-client.com_group.topic.publish.failure").count == 4 - metrics.counter("hermes-client.com_group.topic.publish.attempt").count == 1 - metrics.counter("hermes-client.com_group.topic.publish.retry.success").count == 0 - metrics.counter("hermes-client.com_group.topic.publish.retry.failure").count == 3 - metrics.counter("hermes-client.com_group.topic.publish.retry.attempt").count == 1 - } - - def "should update retries metrics"() { - given: - ReactiveHermesClient client1 = hermesClient(failingHermesSender(2)) - .withRetrySleep(0) - .withRetries(4) - .withMetrics(metricsProvider).build() - - ReactiveHermesClient client2 = hermesClient(failingHermesSender(5)) - .withRetrySleep(0) - .withRetries(6) - .withMetrics(metricsProvider).build() - - ReactiveHermesClient client3 = hermesClient(failingHermesSender(3)) - .withRetrySleep(0) - .withRetries(2) - .withMetrics(metricsProvider).build() - - when: - silence({ client1.publish("com.group.topic", "123").block() }) - silence({ client2.publish("com.group.topic", "456").block() }) - silence({ client3.publish("com.group.topic", "789").block() }) - - then: - metrics.counter("hermes-client.com_group.topic.failure").count == 10 - metrics.counter("hermes-client.com_group.topic.retries.exhausted").count == 1 - metrics.counter("hermes-client.com_group.topic.retries.success").count == 2 - metrics.counter("hermes-client.com_group.topic.retries.count").count == 9 - metrics.histogram("hermes-client.com_group.topic.retries.attempts").getSnapshot().getMin() == 2 - metrics.histogram("hermes-client.com_group.topic.retries.attempts").getSnapshot().getMax() == 5 - metrics.timers.containsKey("hermes-client.com_group.topic.latency") - - metrics.counter("hermes-client.com_group.topic.publish.finally.success").count == 2 - metrics.counter("hermes-client.com_group.topic.publish.finally.failure").count == 1 - metrics.counter("hermes-client.com_group.topic.publish.failure").count == 10 - metrics.counter("hermes-client.com_group.topic.publish.attempt").count == 3 - metrics.counter("hermes-client.com_group.topic.publish.retry.success").count == 2 - metrics.counter("hermes-client.com_group.topic.publish.retry.failure").count == 9 - metrics.counter("hermes-client.com_group.topic.publish.retry.attempt").count == 3 - } - - def "should update failure metrics when there is an application-level error"() { - given: - ReactiveHermesClient client1 = hermesClient(badRequestHermesSender()) - .withRetrySleep(0) - .withRetries(4) - .withMetrics(metricsProvider).build() - - ReactiveHermesClient client2 = hermesClient(badRequestHermesSender()) - .withRetrySleep(0) - .withRetries(6) - .withMetrics(metricsProvider).build() - - ReactiveHermesClient client3 = hermesClient(badRequestHermesSender()) - .withRetrySleep(0) - .withRetries(2) - .withMetrics(metricsProvider).build() - - when: - silence({ client1.publish("com.group.topic", "123").block() }) - silence({ client2.publish("com.group.topic", "456").block() }) - silence({ client3.publish("com.group.topic", "789").block() }) - - then: - metrics.counter("hermes-client.com_group.topic.publish.finally.success").count == 0 - metrics.counter("hermes-client.com_group.topic.publish.finally.failure").count == 3 - metrics.counter("hermes-client.com_group.topic.publish.failure").count == 3 - metrics.counter("hermes-client.com_group.topic.publish.attempt").count == 3 - metrics.counter("hermes-client.com_group.topic.publish.retry.success").count == 0 - metrics.counter("hermes-client.com_group.topic.publish.retry.failure").count == 0 - metrics.counter("hermes-client.com_group.topic.publish.retry.attempt").count == 0 - } - - private Mono successMono(HermesMessage message) { - return Mono.just(HermesResponseBuilder.hermesResponse(message).withHttpStatus(201).build()) - } - - private Mono badRequestMono(HermesMessage message) { - return Mono.just(HermesResponseBuilder.hermesResponse(message).withHttpStatus(400).build()) - } - - private Mono failingMono(Throwable throwable) { - return Mono.error(throwable) - } - - private ReactiveHermesSender failingHermesSender(int errorNo) { - new ReactiveHermesSender() { - int i = 0 - @Override - Mono sendReactively(URI uri, HermesMessage message) { - i++ - if (i <= errorNo) { - return failingMono(new RuntimeException()) - } - return successMono(message) - } - } - } - - private ReactiveHermesSender delayedHermesSender(Duration sendLatencyMs) { - new ReactiveHermesSender() { - @Override - Mono sendReactively(URI uri, HermesMessage message) { - Thread.sleep(sendLatencyMs.toMillis()) - return successMono(message) - } - } - } - - private ReactiveHermesSender badRequestHermesSender() { - new ReactiveHermesSender() { - @Override - Mono sendReactively(URI uri, HermesMessage message) { - return badRequestMono(message) - } - } - } - - private void silence(Runnable runnable) { - try { - runnable.run() - } catch (Exception ex) { - // do nothing - } - } - -} diff --git a/hermes-common/build.gradle b/hermes-common/build.gradle index ccf959276b..d1e850d4d6 100644 --- a/hermes-common/build.gradle +++ b/hermes-common/build.gradle @@ -25,23 +25,21 @@ dependencies { api group: 'tech.allegro.schema.json2avro', name: 'converter', version: versions.json2avro api group: 'org.apache.commons', name: 'commons-collections4', version: '4.4' - implementation group: 'commons-codec', name: 'commons-codec', version: '1.9' + implementation group: 'commons-codec', name: 'commons-codec', version: '1.16.1' implementation group: 'com.google.guava', name: 'guava', version: versions.guava api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: versions.jackson api group: 'org.apache.avro', name: 'avro', version: versions.avro - api group: 'com.jayway.jsonpath', name: 'json-path', version: '2.5.0' + api group: 'com.jayway.jsonpath', name: 'json-path', version: '2.9.0' - implementation group: 'io.dropwizard.metrics', name: 'metrics-graphite', version: versions.dropwizard_metrics - implementation group: 'io.dropwizard.metrics', name: 'metrics-jvm', version: versions.dropwizard_metrics - implementation group: 'org.mpierce.metrics.reservoir', name: 'hdrhistogram-metrics-reservoir', version: '1.1.0' + implementation group: 'io.dropwizard.metrics', name: 'metrics-core', version: versions.dropwizard_metrics - implementation group: 'com.google.code.findbugs', name: 'annotations', version: '3.0.0' + implementation group: 'com.google.code.findbugs', name: 'annotations', version: '3.0.1' api group: 'io.micrometer', name: 'micrometer-core', version: versions.micrometer_metrics api group: 'io.micrometer', name: 'micrometer-registry-prometheus', version: versions.micrometer_metrics - implementation group: 'org.slf4j', name: 'log4j-over-slf4j', version: '2.0.4' - implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.7' + implementation group: 'org.slf4j', name: 'log4j-over-slf4j', version: '2.0.13' + implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.14' api(group: 'org.apache.kafka', name: 'kafka-clients', version: versions.kafka) { exclude group: 'net.sf.jopt-simple' } @@ -50,12 +48,10 @@ dependencies { testImplementation project(':hermes-test-helper') - testImplementation group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0' + testImplementation group: 'jakarta.servlet', name: 'jakarta.servlet-api', version: '6.0.0' testImplementation group: 'org.spockframework', name: 'spock-core', version: versions.spock testImplementation group: 'org.spockframework', name: 'spock-junit4', version: versions.spock - testImplementation (group: 'com.jayway.awaitility', name: 'awaitility-groovy', version: '1.7.0') { - exclude group: 'org.codehaus.groovy', module: 'groovy-all' - } + testImplementation group: 'org.awaitility', name: 'awaitility-groovy', version: '4.2.1' testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: versions.junit_jupiter } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/di/factories/GraphiteParameters.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/di/factories/GraphiteParameters.java deleted file mode 100644 index 84314096c4..0000000000 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/di/factories/GraphiteParameters.java +++ /dev/null @@ -1,10 +0,0 @@ -package pl.allegro.tech.hermes.common.di.factories; - -public interface GraphiteParameters { - - String getPrefix(); - - String getHost(); - - int getPort(); -} diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/di/factories/MetricRegistryFactory.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/di/factories/MetricRegistryFactory.java deleted file mode 100644 index 1d1de61579..0000000000 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/di/factories/MetricRegistryFactory.java +++ /dev/null @@ -1,107 +0,0 @@ -package pl.allegro.tech.hermes.common.di.factories; - -import com.codahale.metrics.ConsoleReporter; -import com.codahale.metrics.Metric; -import com.codahale.metrics.MetricAttribute; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.MetricSet; -import com.codahale.metrics.graphite.Graphite; -import com.codahale.metrics.graphite.GraphiteReporter; -import com.codahale.metrics.jvm.FileDescriptorRatioGauge; -import com.codahale.metrics.jvm.GarbageCollectorMetricSet; -import com.codahale.metrics.jvm.MemoryUsageGaugeSet; -import com.google.common.base.Joiner; -import com.google.common.collect.Sets; -import jakarta.inject.Named; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; -import pl.allegro.tech.hermes.common.metric.MetricRegistryWithHdrHistogramReservoir; -import pl.allegro.tech.hermes.common.util.InstanceIdResolver; - -import java.net.InetSocketAddress; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -public class MetricRegistryFactory { - - private static final Logger logger = LoggerFactory.getLogger(MetricRegistryFactory.class); - private final MetricRegistryParameters metricRegistryParameters; - private final GraphiteParameters graphiteParameters; - private final InstanceIdResolver instanceIdResolver; - private final String moduleName; - - public MetricRegistryFactory(MetricRegistryParameters metricRegistryParameters, - GraphiteParameters graphiteParameters, - InstanceIdResolver instanceIdResolver, - @Named("moduleName") String moduleName) { - this.metricRegistryParameters = metricRegistryParameters; - this.graphiteParameters = graphiteParameters; - this.instanceIdResolver = instanceIdResolver; - this.moduleName = moduleName; - } - - public MetricRegistry provide() { - MetricRegistry registry = new MetricRegistryWithHdrHistogramReservoir(); - - if (metricRegistryParameters.isGraphiteReporterEnabled()) { - String prefix = Joiner.on(".").join( - graphiteParameters.getPrefix(), - moduleName, - instanceIdResolver.resolve().replaceAll("\\.", HermesMetrics.REPLACEMENT_CHAR)); - - GraphiteReporter - .forRegistry(registry) - .prefixedWith(prefix) - .disabledMetricAttributes(getDisabledAttributesFromConfig()) - .build(new Graphite(new InetSocketAddress( - graphiteParameters.getHost(), - graphiteParameters.getPort() - ))) - .start(metricRegistryParameters.getReportPeriod().toSeconds(), TimeUnit.SECONDS); - } - if (metricRegistryParameters.isConsoleReporterEnabled()) { - ConsoleReporter.forRegistry(registry).build().start( - metricRegistryParameters.getReportPeriod().toSeconds(), TimeUnit.SECONDS - ); - } - registerJvmMetrics(registry); - - return registry; - } - - private void registerJvmMetrics(MetricRegistry metricRegistry) { - registerAll("jvm.gc", new GarbageCollectorMetricSet(), metricRegistry); - registerAll("jvm.memory", new MemoryUsageGaugeSet(), metricRegistry); - metricRegistry.register("jvm.descriptors", new FileDescriptorRatioGauge()); - } - - private void registerAll(String prefix, MetricSet metricSet, MetricRegistry registry) { - for (Map.Entry entry : metricSet.getMetrics().entrySet()) { - if (entry.getValue() instanceof MetricSet) { - registerAll(prefix + "." + entry.getKey(), (MetricSet) entry.getValue(), registry); - } else { - registry.register(prefix + "." + entry.getKey(), entry.getValue()); - } - } - } - - private Set getDisabledAttributesFromConfig() { - Set disabledAttributes = Sets.newHashSet(); - String disabledAttributesFromConfig = metricRegistryParameters.getDisabledAttributes(); - List disabledAttributesList = Arrays.asList(disabledAttributesFromConfig.split("\\s*,\\s*")); - - disabledAttributesList.forEach(singleAttribute -> { - try { - disabledAttributes.add(MetricAttribute.valueOf(singleAttribute)); - } catch (IllegalArgumentException e) { - logger.warn("Failed to add disabled attribute from config: {}", e.getMessage()); - } - }); - - return disabledAttributes; - } -} diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/di/factories/MetricRegistryParameters.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/di/factories/MetricRegistryParameters.java deleted file mode 100644 index d112cea526..0000000000 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/di/factories/MetricRegistryParameters.java +++ /dev/null @@ -1,16 +0,0 @@ -package pl.allegro.tech.hermes.common.di.factories; - -import java.time.Duration; - -public interface MetricRegistryParameters { - - boolean isZookeeperReporterEnabled(); - - boolean isGraphiteReporterEnabled(); - - boolean isConsoleReporterEnabled(); - - String getDisabledAttributes(); - - Duration getReportPeriod(); -} diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/message/converter/AvroBinaryDecoders.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/message/converter/AvroBinaryDecoders.java index c77be92b29..1d092f655b 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/message/converter/AvroBinaryDecoders.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/message/converter/AvroBinaryDecoders.java @@ -5,7 +5,7 @@ import org.apache.avro.generic.GenericRecord; import org.apache.avro.io.BinaryDecoder; import org.apache.avro.io.DecoderFactory; -import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import tech.allegro.schema.json2avro.converter.AvroConversionException; import java.io.ByteArrayInputStream; diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/ConsumerMetrics.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/ConsumerMetrics.java index 8ef5a5d086..c6b3bb2af0 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/ConsumerMetrics.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/ConsumerMetrics.java @@ -9,20 +9,15 @@ import java.util.function.ToDoubleFunction; -import static pl.allegro.tech.hermes.common.metric.Gauges.BATCH_BUFFER_AVAILABLE_BYTES; -import static pl.allegro.tech.hermes.common.metric.Gauges.BATCH_BUFFER_TOTAL_BYTES; -import static pl.allegro.tech.hermes.common.metric.Gauges.THREADS; import static pl.allegro.tech.hermes.common.metric.SubscriptionTagsFactory.subscriptionTags; public class ConsumerMetrics { - private final HermesMetrics hermesMetrics; private final MeterRegistry meterRegistry; private final GaugeRegistrar gaugeRegistrar; - public ConsumerMetrics(HermesMetrics hermesMetrics, MeterRegistry meterRegistry) { - this.hermesMetrics = hermesMetrics; + public ConsumerMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; - this.gaugeRegistrar = new GaugeRegistrar(meterRegistry, hermesMetrics); + this.gaugeRegistrar = new GaugeRegistrar(meterRegistry); } public void registerQueueUtilizationGauge(T obj, String queueName, ToDoubleFunction f) { @@ -31,31 +26,28 @@ public void registerQueueUtilizationGauge(T obj, String queueName, ToDouble public HermesCounter queueFailuresCounter(String name) { return HermesCounters.from( - meterRegistry.counter("queue." + name + ".failures"), - hermesMetrics.counter("queue." + name + ".failures") + meterRegistry.counter("queue." + name + ".failures") ); } public void registerConsumerProcessesThreadsGauge(T obj, ToDoubleFunction f) { - gaugeRegistrar.registerGauge(THREADS, "consumer-processes.threads", obj, f); + gaugeRegistrar.registerGauge("consumer-processes.threads", obj, f); } public void registerRunningConsumerProcessesGauge(T obj, ToDoubleFunction f) { - hermesMetrics.registerRunningConsumerProcessesCountGauge(() -> (int) f.applyAsDouble(obj)); meterRegistry.gauge("consumer-processes.running", obj, f); } public void registerDyingConsumerProcessesGauge(T obj, ToDoubleFunction f) { - hermesMetrics.registerDyingConsumerProcessesCountGauge(() -> (int) f.applyAsDouble(obj)); meterRegistry.gauge("consumer-processes.dying", obj, f); } public void registerBatchBufferTotalBytesGauge(T obj, ToDoubleFunction f) { - gaugeRegistrar.registerGauge(BATCH_BUFFER_TOTAL_BYTES, "batch-buffer.total-bytes", obj, f); + gaugeRegistrar.registerGauge("batch-buffer.total-bytes", obj, f); } public void registerBatchBufferAvailableBytesGauge(T obj, ToDoubleFunction f) { - gaugeRegistrar.registerGauge(BATCH_BUFFER_AVAILABLE_BYTES, "batch-buffer.available-bytes", obj, f); + gaugeRegistrar.registerGauge("batch-buffer.available-bytes", obj, f); } public HermesCounter oAuthSubscriptionTokenRequestCounter(Subscription subscription, String providerName) { @@ -63,29 +55,25 @@ public HermesCounter oAuthSubscriptionTokenRequestCounter(Subscription subscript meterRegistry.counter("oauth.token-requests", Tags.concat( subscriptionTags(subscription.getQualifiedName()), "provider", providerName - )), - hermesMetrics.oAuthSubscriptionTokenRequestMeter(subscription, providerName) + )) ); } public HermesTimer oAuthProviderLatencyTimer(String providerName) { return HermesTimer.from( - meterRegistry.timer("oauth.token-request-latency", Tags.of("provider", providerName)), - hermesMetrics.oAuthProviderLatencyTimer(providerName) + meterRegistry.timer("oauth.token-request-latency", Tags.of("provider", providerName)) ); } public HermesCounter processedSignalsCounter(String name) { return HermesCounters.from( - meterRegistry.counter("signals.processed", Tags.of("signal", name)), - hermesMetrics.counter("supervisor.signal." + name) + meterRegistry.counter("signals.processed", Tags.of("signal", name)) ); } public HermesCounter droppedSignalsCounter(String name) { return HermesCounters.from( - meterRegistry.counter("signals.dropped", Tags.of("signal", name)), - hermesMetrics.counter("supervisor.signal.dropped." + name) + meterRegistry.counter("signals.dropped", Tags.of("signal", name)) ); } } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/ConsumerSenderMetrics.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/ConsumerSenderMetrics.java index 76bba6dde7..d3d8a3c80e 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/ConsumerSenderMetrics.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/ConsumerSenderMetrics.java @@ -13,33 +13,27 @@ public class ConsumerSenderMetrics { - private final HermesMetrics hermesMetrics; private final MeterRegistry meterRegistry; private final GaugeRegistrar gaugeRegistrar; - ConsumerSenderMetrics(HermesMetrics hermesMetrics, MeterRegistry meterRegistry) { - this.hermesMetrics = hermesMetrics; + ConsumerSenderMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; - this.gaugeRegistrar = new GaugeRegistrar(meterRegistry, hermesMetrics); + this.gaugeRegistrar = new GaugeRegistrar(meterRegistry); } public void registerRequestQueueSizeGauge(T obj, ToDoubleFunction f) { - hermesMetrics.registerConsumerSenderRequestQueueSize(() -> (int) f.applyAsDouble(obj)); meterRegistry.gauge("http-clients.request-queue-size", obj, f); } public void registerHttp1SerialClientRequestQueueSizeGauge(T obj, ToDoubleFunction f) { - hermesMetrics.registerConsumerSenderHttp1SerialClientRequestQueueSize(() -> (int) f.applyAsDouble(obj)); meterRegistry.gauge("http-clients.serial.http1.request-queue-size", obj, f); } public void registerHttp1BatchClientRequestQueueSizeGauge(T obj, ToDoubleFunction f) { - hermesMetrics.registerConsumerSenderHttp1BatchClientRequestQueueSize(() -> (int) f.applyAsDouble(obj)); meterRegistry.gauge("http-clients.batch.http1.request-queue-size", obj, f); } public void registerHttp2RequestQueueSizeGauge(T obj, ToDoubleFunction f) { - hermesMetrics.registerConsumerSenderHttp2RequestQueueSize(() -> (int) f.applyAsDouble(obj)); meterRegistry.gauge("http-clients.serial.http2.request-queue-size", obj, f); } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Counters.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Counters.java deleted file mode 100644 index 486c053e38..0000000000 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Counters.java +++ /dev/null @@ -1,17 +0,0 @@ -package pl.allegro.tech.hermes.common.metric; - -import static pl.allegro.tech.hermes.metrics.PathsCompiler.GROUP; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.SUBSCRIPTION; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.TOPIC; - -public class Counters { - - public static final String PUBLISHED = "published." + GROUP + "." + TOPIC; - public static final String DELIVERED = "delivered." + GROUP + "." + TOPIC + "." + SUBSCRIPTION; - public static final String DISCARDED = "discarded." + GROUP + "." + TOPIC + "." + SUBSCRIPTION; - public static final String RETRIES = "retries." + GROUP + "." + TOPIC + "." + SUBSCRIPTION; - public static final String MAXRATE_RATE_HISTORY_FAILURES = - "consumers-rate.max-rate.node." + GROUP + "." + TOPIC + "." + SUBSCRIPTION + ".history.failures"; - public static final String MAXRATE_FETCH_FAILURES = - "consumers-rate.max-rate.node." + GROUP + "." + TOPIC + "." + SUBSCRIPTION + ".fetch.failures"; -} diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/DeserializationMetrics.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/DeserializationMetrics.java index e8628afbf8..3efe8fac71 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/DeserializationMetrics.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/DeserializationMetrics.java @@ -1,50 +1,43 @@ package pl.allegro.tech.hermes.common.metric; +import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tags; import pl.allegro.tech.hermes.metrics.HermesCounter; import pl.allegro.tech.hermes.metrics.counters.HermesCounters; -import static com.codahale.metrics.MetricRegistry.name; - public class DeserializationMetrics { - private final HermesMetrics hermesMetrics; private final MeterRegistry meterRegistry; private static final String BASE_PATH = "content.avro.deserialization"; private static final String ERRORS_PATH = BASE_PATH + ".errors"; - public DeserializationMetrics(HermesMetrics hermesMetrics, MeterRegistry meterRegistry) { - this.hermesMetrics = hermesMetrics; + public DeserializationMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; } public HermesCounter errorsForHeaderSchemaVersion() { return HermesCounters.from( - deserializationErrorCounter("headerSchemaVersion"), - hermesMetrics.counter(name(ERRORS_PATH, "headerSchemaVersion")) + deserializationErrorCounter("headerSchemaVersion") ); } public HermesCounter errorsForHeaderSchemaId() { return HermesCounters.from( - deserializationErrorCounter("headerSchemaId"), - hermesMetrics.counter(name(ERRORS_PATH, "headerSchemaId")) + deserializationErrorCounter("headerSchemaId") ); } public HermesCounter errorsForSchemaIdAwarePayload() { return HermesCounters.from( - deserializationErrorCounter("payloadWithSchemaId"), - hermesMetrics.counter(name(ERRORS_PATH, "payloadWithSchemaId")) + deserializationErrorCounter("payloadWithSchemaId") ); } public HermesCounter errorsForSchemaVersionTruncation() { return HermesCounters.from( - deserializationErrorCounter("schemaVersionTruncation"), - hermesMetrics.counter(name(ERRORS_PATH, "schemaVersionTruncation")) + deserializationErrorCounter("schemaVersionTruncation") ); } @@ -54,40 +47,35 @@ private io.micrometer.core.instrument.Counter deserializationErrorCounter(String public HermesCounter missingSchemaIdInPayload() { return HermesCounters.from( - meterRegistry.counter(name(BASE_PATH, "missing_schemaIdInPayload")), - hermesMetrics.counter(name(BASE_PATH, "missed", "schemaIdInPayload")) + meterRegistry.counter(BASE_PATH + ".missing_schemaIdInPayload") ); } public HermesCounter usingHeaderSchemaVersion() { return HermesCounters.from( - deserializationAttemptCounter("headerSchemaVersion"), - hermesMetrics.counter(name(BASE_PATH, "using", "headerSchemaVersion")) + deserializationAttemptCounter("headerSchemaVersion") ); } public HermesCounter usingHeaderSchemaId() { return HermesCounters.from( - deserializationAttemptCounter("headerSchemaId"), - hermesMetrics.counter(name(BASE_PATH, "using", "headerSchemaId")) + deserializationAttemptCounter("headerSchemaId") ); } public HermesCounter usingSchemaIdAware() { return HermesCounters.from( - deserializationAttemptCounter("payloadWithSchemaId"), - hermesMetrics.counter(name(BASE_PATH, "using", "schemaIdAware")) + deserializationAttemptCounter("payloadWithSchemaId") ); } public HermesCounter usingSchemaVersionTruncation() { return HermesCounters.from( - deserializationAttemptCounter("schemaVersionTruncation"), - hermesMetrics.counter(name(BASE_PATH, "using", "schemaVersionTruncation")) + deserializationAttemptCounter("schemaVersionTruncation") ); } - private io.micrometer.core.instrument.Counter deserializationAttemptCounter(String deserializationType) { + private Counter deserializationAttemptCounter(String deserializationType) { return meterRegistry.counter(BASE_PATH, Tags.of("deserialization_type", deserializationType)); } } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/GaugeRegistrar.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/GaugeRegistrar.java index 2d2a7b4c4d..cbcb86ba84 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/GaugeRegistrar.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/GaugeRegistrar.java @@ -8,40 +8,22 @@ public class GaugeRegistrar { private final MeterRegistry meterRegistry; - private final HermesMetrics hermesMetrics; - public GaugeRegistrar(MeterRegistry meterRegistry, HermesMetrics hermesMetrics) { + public GaugeRegistrar(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; - this.hermesMetrics = hermesMetrics; - } - - public void registerGauge(String graphiteName, - String prometheusName, - T stateObj, - ToDoubleFunction f, - Iterable tags) { - meterRegistry.gauge(prometheusName, tags, stateObj, f); - hermesMetrics.registerGauge(graphiteName, () -> f.applyAsDouble(stateObj)); - } - - public void registerGauge(String graphiteName, - String prometheusName, - T stateObj, - ToDoubleFunction f) { - registerGauge(graphiteName, prometheusName, stateObj, f, Tags.empty()); } public void registerGauge(String name, T stateObj, ToDoubleFunction f) { - registerGauge(name, name, stateObj, f); + registerGauge(name, stateObj, f, Tags.empty()); } public void registerGauge(String name, T stateObj, ToDoubleFunction f, Iterable tags) { - registerGauge(name, name, stateObj, f, tags); + meterRegistry.gauge(name, tags, stateObj, f); } } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Gauges.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Gauges.java index c75cbfcdea..5202b7355d 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Gauges.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Gauges.java @@ -1,37 +1,17 @@ package pl.allegro.tech.hermes.common.metric; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.GROUP; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.SUBSCRIPTION; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.TOPIC; - public class Gauges { - public static final String BATCH_BUFFER_TOTAL_BYTES = "batch-buffer-total-bytes"; - public static final String BATCH_BUFFER_AVAILABLE_BYTES = "batch-buffer-available-bytes"; - public static final String THREADS = "threads"; public static final String INFLIGHT_REQUESTS = "inflight-requests"; - public static final String OUTPUT_RATE = "output-rate." + GROUP + "." + TOPIC + "." + SUBSCRIPTION; public static final String BACKUP_STORAGE_SIZE = "backup-storage.size"; - public static final String MAX_RATE_CALCULATION_DURATION = "consumers-rate.max-rate.coordinator.duration"; - public static final String MAX_RATE_VALUE = - "consumers-rate.max-rate.node." + GROUP + "." + TOPIC + "." + SUBSCRIPTION + ".max-rate"; - public static final String MAX_RATE_ACTUAL_RATE_VALUE = - "consumers-rate.max-rate.node." + GROUP + "." + TOPIC + "." + SUBSCRIPTION + ".rate"; - public static final String RUNNING_CONSUMER_PROCESSES_COUNT = "consumer-processes.running-consumer-processes.count"; - public static final String DYING_CONSUMER_PROCESSES_COUNT = "consumer-processes.dying-consumer-processes.count"; - public static final String CONSUMER_SENDER_REQUEST_QUEUE_SIZE = "http-clients.request-queue-size"; - public static final String CONSUMER_SENDER_HTTP_1_SERIAL_CLIENT_REQUEST_QUEUE_SIZE = "http-clients.serial.http1.request-queue-size"; public static final String CONSUMER_SENDER_HTTP_1_SERIAL_CLIENT_ACTIVE_CONNECTIONS = "http-clients.serial.http1.active-connections"; public static final String CONSUMER_SENDER_HTTP_1_SERIAL_CLIENT_IDLE_CONNECTIONS = "http-clients.serial.http1.idle-connections"; - public static final String CONSUMER_SENDER_HTTP_1_BATCH_CLIENT_REQUEST_QUEUE_SIZE = "http-clients.batch.http1.request-queue-size"; public static final String CONSUMER_SENDER_HTTP_1_BATCH_CLIENT_ACTIVE_CONNECTIONS = "http-clients.batch.http1.active-connections"; public static final String CONSUMER_SENDER_HTTP_1_BATCH_CLIENT_IDLE_CONNECTIONS = "http-clients.batch.http1.idle-connections"; - public static final String CONSUMER_SENDER_HTTP_2_SERIAL_CLIENT_REQUEST_QUEUE_SIZE = "http-clients.serial.http2.request-queue-size"; public static final String CONSUMER_SENDER_HTTP_2_SERIAL_CLIENT_CONNECTIONS = "http-clients.serial.http2.connections"; public static final String CONSUMER_SENDER_HTTP_2_SERIAL_CLIENT_PENDING_CONNECTIONS = "http-clients.serial.http2.pending-connections"; - public static final String INFLIGHT = "inflight." + GROUP + "." + TOPIC + "." + SUBSCRIPTION + ".count"; } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/HermesMetrics.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/HermesMetrics.java deleted file mode 100644 index 23d477ac6e..0000000000 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/HermesMetrics.java +++ /dev/null @@ -1,274 +0,0 @@ -package pl.allegro.tech.hermes.common.metric; - -import com.codahale.metrics.Counter; -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.Meter; -import com.codahale.metrics.MetricFilter; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Timer; -import pl.allegro.tech.hermes.api.Subscription; -import pl.allegro.tech.hermes.api.SubscriptionName; -import pl.allegro.tech.hermes.api.TopicName; -import pl.allegro.tech.hermes.metrics.PathContext; -import pl.allegro.tech.hermes.metrics.PathsCompiler; - -import static pl.allegro.tech.hermes.common.metric.Histograms.INFLIGHT_TIME; -import static pl.allegro.tech.hermes.common.metric.Meters.ERRORS_HTTP_BY_CODE; -import static pl.allegro.tech.hermes.common.metric.Meters.ERRORS_HTTP_BY_FAMILY; -import static pl.allegro.tech.hermes.common.metric.Meters.ERRORS_OTHER; -import static pl.allegro.tech.hermes.common.metric.Meters.ERRORS_TIMEOUTS; -import static pl.allegro.tech.hermes.common.metric.Meters.SUBSCRIPTION_STATUS; -import static pl.allegro.tech.hermes.metrics.PathContext.pathContext; - -public class HermesMetrics { - - public static final String REPLACEMENT_CHAR = "_"; - - private final MetricRegistry metricRegistry; - private final PathsCompiler pathCompiler; - - public HermesMetrics( - MetricRegistry metricRegistry, - PathsCompiler pathCompiler) { - this.metricRegistry = metricRegistry; - this.pathCompiler = pathCompiler; - } - - public static String escapeDots(String value) { - return value.replaceAll("\\.", REPLACEMENT_CHAR); - } - - public Timer timer(String metric) { - return metricRegistry.timer(metricRegistryName(metric)); - } - - public Timer timer(String metric, TopicName topicName) { - return metricRegistry.timer(metricRegistryName(metric, topicName)); - } - - public Timer timer(String metric, TopicName topicName, String name) { - return metricRegistry.timer(metricRegistryName(metric, topicName, name)); - } - - public Meter meter(String metric) { - return metricRegistry.meter(metricRegistryName(metric)); - } - - public Meter meter(String metric, TopicName topicName, String name) { - return metricRegistry.meter(metricRegistryName(metric, topicName, name)); - } - - public Meter meter(String metric, TopicName topicName) { - return metricRegistry.meter(metricRegistryName(metric, topicName)); - } - - public Meter httpStatusCodeMeter(int statusCode) { - return metricRegistry.meter(pathCompiler.compile(Meters.STATUS_CODES, pathContext().withHttpCode(statusCode).build())); - } - - public Meter httpStatusCodeMeter(int statusCode, TopicName topicName) { - return metricRegistry.meter(pathCompiler.compile(Meters.TOPIC_STATUS_CODES, - pathContext().withHttpCode(statusCode).withGroup(topicName.getGroupName()).withTopic(topicName.getName()).build())); - } - - public Histogram histogram(String metric) { - return metricRegistry.histogram(metricRegistryName(metric)); - } - - public Counter counter(String metric) { - return metricRegistry.counter(metricRegistryName(metric)); - } - - public Counter counter(String metric, TopicName topicName) { - return metricRegistry.counter(metricRegistryName(metric, topicName)); - } - - public Counter counter(String metric, TopicName topicName, String name) { - return metricRegistry.counter(metricRegistryName(metric, topicName, name)); - } - - public void registerProducerInflightRequest(Gauge gauge) { - metricRegistry.register(metricRegistryName(Gauges.INFLIGHT_REQUESTS), gauge); - } - - public void registerMessageRepositorySizeGauge(Gauge gauge) { - metricRegistry.register(metricRegistryName(Gauges.BACKUP_STORAGE_SIZE), gauge); - } - - public void registerConsumerSenderRequestQueueSize(Gauge gauge) { - metricRegistry.register(metricRegistryName(Gauges.CONSUMER_SENDER_REQUEST_QUEUE_SIZE), gauge); - } - - public void registerConsumerSenderHttp1SerialClientRequestQueueSize(Gauge gauge) { - metricRegistry.register(metricRegistryName(Gauges.CONSUMER_SENDER_HTTP_1_SERIAL_CLIENT_REQUEST_QUEUE_SIZE), gauge); - } - - public void registerConsumerSenderHttp1BatchClientRequestQueueSize(Gauge gauge) { - metricRegistry.register(metricRegistryName(Gauges.CONSUMER_SENDER_HTTP_1_BATCH_CLIENT_REQUEST_QUEUE_SIZE), gauge); - } - - public void registerConsumerSenderHttp2RequestQueueSize(Gauge gauge) { - metricRegistry.register(metricRegistryName(Gauges.CONSUMER_SENDER_HTTP_2_SERIAL_CLIENT_REQUEST_QUEUE_SIZE), gauge); - } - - public void registerInflightGauge(SubscriptionName subscription, Gauge gauge) { - registerGauge(metricRegistryName(Gauges.INFLIGHT, subscription.getTopicName(), subscription.getName()), gauge); - } - - public void unregisterInflightGauge(SubscriptionName subscription) { - unregister(Gauges.INFLIGHT, subscription); - } - - public static void close(Timer.Context... timers) { - for (Timer.Context timer : timers) { - if (timer != null) { - timer.close(); - } - } - } - - public void registerGauge(String name, Gauge gauge) { - String path = pathCompiler.compile(name); - if (!metricRegistry.getGauges().containsKey(name)) { - metricRegistry.register(path, gauge); - } - } - - public void registerGauge(String name, SubscriptionName subscription, Gauge gauge) { - if (!metricRegistry.getGauges().containsKey(name)) { - metricRegistry.register(metricRegistryName(name, subscription.getTopicName(), subscription.getName()), gauge); - } - } - - public void unregister(String metric, SubscriptionName subscription) { - metricRegistry.remove(metricRegistryName(metric, subscription.getTopicName(), subscription.getName())); - } - - public void unregister(String name) { - String path = pathCompiler.compile(name); - metricRegistry.remove(path); - } - - private String metricRegistryName(String metricDisplayName, TopicName topicName, String subscription) { - PathContext pathContext = PathContext.pathContext() - .withGroup(escapeDots(topicName.getGroupName())) - .withTopic(escapeDots(topicName.getName())) - .withSubscription(escapeDots(subscription)) - .build(); - - return pathCompiler.compile(metricDisplayName, pathContext); - } - - private String metricRegistryName(String metricDisplayName, TopicName topicName) { - PathContext pathContext = PathContext.pathContext() - .withGroup(escapeDots(topicName.getGroupName())) - .withTopic(escapeDots(topicName.getName())).build(); - - return pathCompiler.compile(metricDisplayName, pathContext); - } - - private String metricRegistryName(String metricDisplayName) { - return pathCompiler.compile(metricDisplayName); - } - - public Timer schemaTimer(String schemaMetric) { - return metricRegistry.timer(pathCompiler.compile(schemaMetric, pathContext().withSchemaRepoType("schema-registry").build())); - } - - private Gauge registerExecutorGauge(String path, String executorName, Gauge gauge) { - return metricRegistry.register(pathCompiler.compile(path, pathContext().withExecutorName(executorName).build()), gauge); - } - - private Counter executorCounter(String path, String executorName) { - return metricRegistry.counter(pathCompiler.compile(path, pathContext().withExecutorName(executorName).build())); - } - - - public Histogram messageContentSizeHistogram() { - return metricRegistry.histogram(pathCompiler.compile(Histograms.GLOBAL_MESSAGE_SIZE)); - } - - public Histogram messageContentSizeHistogram(TopicName topic) { - return metricRegistry.histogram(pathCompiler.compile(Histograms.MESSAGE_SIZE, pathContext() - .withGroup(escapeDots(topic.getGroupName())) - .withTopic(escapeDots(topic.getName())) - .build())); - } - - public Histogram inflightTimeHistogram(SubscriptionName subscription) { - return metricRegistry.histogram(metricRegistryName(INFLIGHT_TIME, subscription.getTopicName(), subscription.getName())); - } - - public void unregisterInflightTimeHistogram(SubscriptionName subscription) { - unregister(INFLIGHT_TIME, subscription); - } - - public void registerConsumerHttpAnswer(SubscriptionName subscription, int statusCode, long count) { - PathContext pathContext = pathContext() - .withGroup(escapeDots(subscription.getTopicName().getGroupName())) - .withTopic(escapeDots(subscription.getTopicName().getName())) - .withSubscription(escapeDots(subscription.getName())) - .withHttpCode(statusCode) - .withHttpCodeFamily(httpStatusFamily(statusCode)) - .build(); - metricRegistry.meter(pathCompiler.compile(ERRORS_HTTP_BY_FAMILY, pathContext)).mark(count); - metricRegistry.meter(pathCompiler.compile(ERRORS_HTTP_BY_CODE, pathContext)).mark(count); - } - - public void unregisterStatusMeters(SubscriptionName subscription) { - String prefix = metricRegistryName(SUBSCRIPTION_STATUS, subscription.getTopicName(), subscription.getName()); - metricRegistry.removeMatching(MetricFilter.startsWith(prefix)); - } - - private String httpStatusFamily(int statusCode) { - return String.format("%dxx", statusCode / 100); - } - - public Meter consumerErrorsTimeoutMeter(SubscriptionName subscription) { - return metricRegistry.meter(metricRegistryName(ERRORS_TIMEOUTS, subscription.getTopicName(), subscription.getName())); - } - - public void unregisterConsumerErrorsTimeoutMeter(SubscriptionName subscription) { - unregister(ERRORS_TIMEOUTS, subscription); - } - - public Meter consumerErrorsOtherMeter(SubscriptionName subscription) { - return metricRegistry.meter(metricRegistryName(ERRORS_OTHER, subscription.getTopicName(), subscription.getName())); - } - - public void unregisterConsumerErrorsOtherMeter(SubscriptionName subscription) { - unregister(ERRORS_OTHER, subscription); - } - - public Timer consumersWorkloadRebalanceDurationTimer(String kafkaCluster) { - PathContext pathContext = pathContext().withKafkaCluster(kafkaCluster).build(); - return metricRegistry.timer(pathCompiler.compile(Timers.CONSUMER_WORKLOAD_REBALANCE_DURATION, pathContext)); - } - - public Timer oAuthProviderLatencyTimer(String oAuthProviderName) { - PathContext pathContext = pathContext() - .withOAuthProvider(escapeDots(oAuthProviderName)) - .build(); - return metricRegistry.timer(pathCompiler.compile(Timers.OAUTH_PROVIDER_TOKEN_REQUEST_LATENCY, pathContext)); - } - - public Meter oAuthSubscriptionTokenRequestMeter(Subscription subscription, String oAuthProviderName) { - PathContext pathContext = pathContext() - .withGroup(escapeDots(subscription.getTopicName().getGroupName())) - .withTopic(escapeDots(subscription.getTopicName().getName())) - .withSubscription(escapeDots(subscription.getName())) - .withOAuthProvider(escapeDots(oAuthProviderName)) - .build(); - return metricRegistry.meter(pathCompiler.compile(Meters.OAUTH_SUBSCRIPTION_TOKEN_REQUEST, pathContext)); - } - - public void registerRunningConsumerProcessesCountGauge(Gauge gauge) { - metricRegistry.register(metricRegistryName(Gauges.RUNNING_CONSUMER_PROCESSES_COUNT), gauge); - } - - public void registerDyingConsumerProcessesCountGauge(Gauge gauge) { - metricRegistry.register(metricRegistryName(Gauges.DYING_CONSUMER_PROCESSES_COUNT), gauge); - } -} - diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Histograms.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Histograms.java index a12b6f58b5..04238a427c 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Histograms.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Histograms.java @@ -1,12 +1,6 @@ package pl.allegro.tech.hermes.common.metric; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.GROUP; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.SUBSCRIPTION; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.TOPIC; public class Histograms { - public static final String MESSAGE_SIZE = "message-size." + GROUP + "." + TOPIC; - public static final String GLOBAL_MESSAGE_SIZE = "message-size"; - public static final String INFLIGHT_TIME = "inflight." + GROUP + "." + TOPIC + "." + SUBSCRIPTION + ".time"; public static final String PERSISTED_UNDELIVERED_MESSAGE_SIZE = "undelivered-messages.persisted.message-size"; } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/MaxRateMetrics.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/MaxRateMetrics.java index f1a759308d..18a458e52b 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/MaxRateMetrics.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/MaxRateMetrics.java @@ -9,55 +9,41 @@ import java.util.function.ToDoubleFunction; import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static pl.allegro.tech.hermes.common.metric.Counters.MAXRATE_FETCH_FAILURES; -import static pl.allegro.tech.hermes.common.metric.Counters.MAXRATE_RATE_HISTORY_FAILURES; -import static pl.allegro.tech.hermes.common.metric.Gauges.MAX_RATE_ACTUAL_RATE_VALUE; -import static pl.allegro.tech.hermes.common.metric.Gauges.MAX_RATE_CALCULATION_DURATION; -import static pl.allegro.tech.hermes.common.metric.Gauges.MAX_RATE_VALUE; -import static pl.allegro.tech.hermes.common.metric.Gauges.OUTPUT_RATE; import static pl.allegro.tech.hermes.common.metric.SubscriptionTagsFactory.subscriptionTags; public class MaxRateMetrics { - private final HermesMetrics hermesMetrics; private final MeterRegistry meterRegistry; - MaxRateMetrics(HermesMetrics hermesMetrics, MeterRegistry meterRegistry) { - this.hermesMetrics = hermesMetrics; + MaxRateMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; } public void registerCalculationDurationInMillisGauge(T obj, ToDoubleFunction f) { - hermesMetrics.registerGauge(MAX_RATE_CALCULATION_DURATION, () -> (int) f.applyAsDouble(obj)); meterRegistry.more().timeGauge("max-rate.calculation.duration", List.of(), obj, MILLISECONDS, f); } public HermesCounter historyUpdateFailuresCounter(SubscriptionName subscription) { return HermesCounters.from( - meterRegistry.counter("max-rate.history-update.failures", subscriptionTags(subscription)), - hermesMetrics.counter(MAXRATE_RATE_HISTORY_FAILURES, subscription.getTopicName(), subscription.getName()) + meterRegistry.counter("max-rate.history-update.failures", subscriptionTags(subscription)) ); } public HermesCounter fetchFailuresCounter(SubscriptionName subscription) { return HermesCounters.from( - meterRegistry.counter("max-rate.fetch.failures", subscriptionTags(subscription)), - hermesMetrics.counter(MAXRATE_FETCH_FAILURES, subscription.getTopicName(), subscription.getName()) + meterRegistry.counter("max-rate.fetch.failures", subscriptionTags(subscription)) ); } public void registerCalculatedRateGauge(SubscriptionName subscription, T obj, ToDoubleFunction f) { - hermesMetrics.registerGauge(MAX_RATE_VALUE, subscription, () -> (int) f.applyAsDouble(obj)); meterRegistry.gauge("max-rate.calculated-rate", subscriptionTags(subscription), obj, f); } public void registerActualRateGauge(SubscriptionName subscription, T obj, ToDoubleFunction f) { - hermesMetrics.registerGauge(MAX_RATE_ACTUAL_RATE_VALUE, subscription, () -> (int) f.applyAsDouble(obj)); meterRegistry.gauge("max-rate.actual-rate", subscriptionTags(subscription), obj, f); } public void registerOutputRateGauge(SubscriptionName subscription, T obj, ToDoubleFunction f) { - hermesMetrics.registerGauge(OUTPUT_RATE, subscription, () -> (int) f.applyAsDouble(obj)); meterRegistry.gauge("max-rate.output-rate", subscriptionTags(subscription), obj, f); } } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Meters.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Meters.java index 9fd5a360f3..4438260971 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Meters.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Meters.java @@ -1,45 +1,12 @@ package pl.allegro.tech.hermes.common.metric; import static pl.allegro.tech.hermes.metrics.PathsCompiler.GROUP; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.HTTP_CODE; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.HTTP_CODE_FAMILY; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.OAUTH_PROVIDER_NAME; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.SUBSCRIPTION; import static pl.allegro.tech.hermes.metrics.PathsCompiler.TOPIC; public class Meters { - public static final String METER = "meter"; - public static final String TOPIC_METER = METER + "." + GROUP + "." + TOPIC; - public static final String SUBSCRIPTION_METER = TOPIC_METER + "." + SUBSCRIPTION; - public static final String FILTERED_METER = SUBSCRIPTION_METER + ".filtered"; - public static final String SUBSCRIPTION_BATCH_METER = TOPIC_METER + "." + SUBSCRIPTION + ".batch"; - public static final String FAILED_METER = "failed-meter"; - public static final String FAILED_TOPIC_METER = FAILED_METER + "." + GROUP + "." + TOPIC; - public static final String FAILED_METER_SUBSCRIPTION = FAILED_TOPIC_METER + "." + SUBSCRIPTION; public static final String THROUGHPUT_BYTES = "throughput"; public static final String TOPIC_THROUGHPUT_BYTES = THROUGHPUT_BYTES + "." + GROUP + "." + TOPIC; - public static final String SUBSCRIPTION_THROUGHPUT_BYTES = TOPIC_THROUGHPUT_BYTES + "." + SUBSCRIPTION; - public static final String STATUS_CODES = "http-status-codes.code" + HTTP_CODE; - public static final String TOPIC_STATUS_CODES = "http-status-codes." + GROUP + "." + TOPIC + ".code" + HTTP_CODE; - public static final String SUBSCRIPTION_STATUS = "status." + GROUP + "." + TOPIC + "." + SUBSCRIPTION; - public static final String ERRORS_TIMEOUTS = SUBSCRIPTION_STATUS + ".errors.timeout"; - public static final String ERRORS_OTHER = SUBSCRIPTION_STATUS + ".errors.other"; - public static final String ERRORS_HTTP_BY_FAMILY = SUBSCRIPTION_STATUS + "." + HTTP_CODE_FAMILY; - public static final String ERRORS_HTTP_BY_CODE = ERRORS_HTTP_BY_FAMILY + "." + HTTP_CODE; - public static final String DISCARDED_METER = "discarded-meter"; - public static final String DISCARDED_TOPIC_METER = DISCARDED_METER + "." + GROUP + "." + TOPIC; - public static final String DISCARDED_SUBSCRIPTION_METER = DISCARDED_TOPIC_METER + "." + SUBSCRIPTION; - public static final String RETRIES_METER = "retries-meter"; - public static final String RETRIES_TOPIC_METER = RETRIES_METER + "." + GROUP + "." + TOPIC; - public static final String RETRIES_SUBSCRIPTION_METER = RETRIES_TOPIC_METER + "." + SUBSCRIPTION; - public static final String DELAYED_PROCESSING = "delayed-processing"; - public static final String TOPIC_DELAYED_PROCESSING = DELAYED_PROCESSING + "." + GROUP + "." + TOPIC; - - public static final String TOPIC_DUPLICATED_MESSAGE = "duplicated-message" + "." + GROUP + "." + TOPIC; - - public static final String OAUTH_SUBSCRIPTION_TOKEN_REQUEST = "oauth.subscription." + GROUP + "." + TOPIC + "." + SUBSCRIPTION - + ".token-request." + OAUTH_PROVIDER_NAME; public static final String PERSISTED_UNDELIVERED_MESSAGES_METER = "undelivered-messages.persisted"; } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/MetricRegistryWithHdrHistogramReservoir.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/MetricRegistryWithHdrHistogramReservoir.java deleted file mode 100644 index a8c931742d..0000000000 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/MetricRegistryWithHdrHistogramReservoir.java +++ /dev/null @@ -1,19 +0,0 @@ -package pl.allegro.tech.hermes.common.metric; - -import com.codahale.metrics.Histogram; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Timer; -import org.mpierce.metrics.reservoir.hdrhistogram.HdrHistogramResetOnSnapshotReservoir; - -public class MetricRegistryWithHdrHistogramReservoir extends MetricRegistry { - - @Override - public Histogram histogram(String name) { - return histogram(name, () -> new Histogram(new HdrHistogramResetOnSnapshotReservoir())); - } - - @Override - public Timer timer(String name) { - return timer(name, () -> new Timer(new HdrHistogramResetOnSnapshotReservoir())); - } -} diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/MetricsFacade.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/MetricsFacade.java index ab57f56456..23f489aaf8 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/MetricsFacade.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/MetricsFacade.java @@ -7,30 +7,11 @@ import java.util.Collection; -import static pl.allegro.tech.hermes.common.metric.Counters.DELIVERED; -import static pl.allegro.tech.hermes.common.metric.Counters.DISCARDED; -import static pl.allegro.tech.hermes.common.metric.Counters.MAXRATE_FETCH_FAILURES; -import static pl.allegro.tech.hermes.common.metric.Counters.MAXRATE_RATE_HISTORY_FAILURES; -import static pl.allegro.tech.hermes.common.metric.Counters.RETRIES; -import static pl.allegro.tech.hermes.common.metric.Gauges.MAX_RATE_ACTUAL_RATE_VALUE; -import static pl.allegro.tech.hermes.common.metric.Gauges.MAX_RATE_VALUE; -import static pl.allegro.tech.hermes.common.metric.Gauges.OUTPUT_RATE; -import static pl.allegro.tech.hermes.common.metric.Meters.DISCARDED_SUBSCRIPTION_METER; -import static pl.allegro.tech.hermes.common.metric.Meters.FAILED_METER_SUBSCRIPTION; -import static pl.allegro.tech.hermes.common.metric.Meters.FILTERED_METER; -import static pl.allegro.tech.hermes.common.metric.Meters.RETRIES_SUBSCRIPTION_METER; -import static pl.allegro.tech.hermes.common.metric.Meters.SUBSCRIPTION_BATCH_METER; -import static pl.allegro.tech.hermes.common.metric.Meters.SUBSCRIPTION_METER; -import static pl.allegro.tech.hermes.common.metric.Meters.SUBSCRIPTION_THROUGHPUT_BYTES; import static pl.allegro.tech.hermes.common.metric.SubscriptionTagsFactory.subscriptionTags; -import static pl.allegro.tech.hermes.common.metric.Timers.CONSUMER_IDLE_TIME; -import static pl.allegro.tech.hermes.common.metric.Timers.RATE_LIMITER_ACQUIRE; -import static pl.allegro.tech.hermes.common.metric.Timers.SUBSCRIPTION_LATENCY; public class MetricsFacade { private final MeterRegistry meterRegistry; - private final HermesMetrics hermesMetrics; private final TopicMetrics topicMetrics; private final SubscriptionMetrics subscriptionMetrics; private final ConsumerMetrics consumerMetrics; @@ -47,23 +28,22 @@ public class MetricsFacade { private final MaxRateMetrics maxRateMetrics; private final BrokerMetrics brokerMetrics; - public MetricsFacade(MeterRegistry meterRegistry, HermesMetrics hermesMetrics) { + public MetricsFacade(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; - this.hermesMetrics = hermesMetrics; - this.topicMetrics = new TopicMetrics(hermesMetrics, meterRegistry); - this.subscriptionMetrics = new SubscriptionMetrics(hermesMetrics, meterRegistry); - this.consumerMetrics = new ConsumerMetrics(hermesMetrics, meterRegistry); - this.trackerElasticSearchMetrics = new TrackerElasticSearchMetrics(hermesMetrics, meterRegistry); - this.persistentBufferMetrics = new PersistentBufferMetrics(hermesMetrics, meterRegistry); - this.producerMetrics = new ProducerMetrics(hermesMetrics, meterRegistry); + this.topicMetrics = new TopicMetrics(meterRegistry); + this.subscriptionMetrics = new SubscriptionMetrics(meterRegistry); + this.consumerMetrics = new ConsumerMetrics(meterRegistry); + this.trackerElasticSearchMetrics = new TrackerElasticSearchMetrics(meterRegistry); + this.persistentBufferMetrics = new PersistentBufferMetrics(meterRegistry); + this.producerMetrics = new ProducerMetrics(meterRegistry); this.executorMetrics = new ExecutorMetrics(meterRegistry); - this.schemaClientMetrics = new SchemaClientMetrics(hermesMetrics, meterRegistry); - this.undeliveredMessagesMetrics = new UndeliveredMessagesMetrics(hermesMetrics, meterRegistry); - this.deserializationMetrics = new DeserializationMetrics(hermesMetrics, meterRegistry); - this.workloadMetrics = new WorkloadMetrics(hermesMetrics, meterRegistry); - this.consumerSenderMetrics = new ConsumerSenderMetrics(hermesMetrics, meterRegistry); - this.offsetCommitsMetrics = new OffsetCommitsMetrics(hermesMetrics, meterRegistry); - this.maxRateMetrics = new MaxRateMetrics(hermesMetrics, meterRegistry); + this.schemaClientMetrics = new SchemaClientMetrics(meterRegistry); + this.undeliveredMessagesMetrics = new UndeliveredMessagesMetrics(meterRegistry); + this.deserializationMetrics = new DeserializationMetrics(meterRegistry); + this.workloadMetrics = new WorkloadMetrics(meterRegistry); + this.consumerSenderMetrics = new ConsumerSenderMetrics(meterRegistry); + this.offsetCommitsMetrics = new OffsetCommitsMetrics(meterRegistry); + this.maxRateMetrics = new MaxRateMetrics(meterRegistry); this.brokerMetrics = new BrokerMetrics(meterRegistry); } @@ -134,28 +114,5 @@ public void unregisterAllMetricsRelatedTo(SubscriptionName subscription) { for (Meter meter : meters) { meterRegistry.remove(meter); } - hermesMetrics.unregister(DISCARDED_SUBSCRIPTION_METER, subscription); - hermesMetrics.unregister(RETRIES_SUBSCRIPTION_METER, subscription); - hermesMetrics.unregister(FAILED_METER_SUBSCRIPTION, subscription); - hermesMetrics.unregister(SUBSCRIPTION_BATCH_METER, subscription); - hermesMetrics.unregister(SUBSCRIPTION_METER, subscription); - hermesMetrics.unregister(DELIVERED, subscription); - hermesMetrics.unregister(DISCARDED, subscription); - hermesMetrics.unregister(RETRIES, subscription); - hermesMetrics.unregisterInflightGauge(subscription); - hermesMetrics.unregisterInflightTimeHistogram(subscription); - hermesMetrics.unregisterConsumerErrorsTimeoutMeter(subscription); - hermesMetrics.unregisterConsumerErrorsOtherMeter(subscription); - hermesMetrics.unregisterStatusMeters(subscription); - hermesMetrics.unregister(OUTPUT_RATE, subscription); - hermesMetrics.unregister(MAX_RATE_ACTUAL_RATE_VALUE, subscription); - hermesMetrics.unregister(MAX_RATE_VALUE, subscription); - hermesMetrics.unregister(MAXRATE_FETCH_FAILURES, subscription); - hermesMetrics.unregister(MAXRATE_RATE_HISTORY_FAILURES, subscription); - hermesMetrics.unregister(CONSUMER_IDLE_TIME, subscription); - hermesMetrics.unregister(FILTERED_METER, subscription); - hermesMetrics.unregister(SUBSCRIPTION_LATENCY, subscription); - hermesMetrics.unregister(RATE_LIMITER_ACQUIRE, subscription); - hermesMetrics.unregister(SUBSCRIPTION_THROUGHPUT_BYTES, subscription); } } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/OffsetCommitsMetrics.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/OffsetCommitsMetrics.java index 84527282a4..b3b1376edb 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/OffsetCommitsMetrics.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/OffsetCommitsMetrics.java @@ -7,46 +7,39 @@ public class OffsetCommitsMetrics { - private final HermesMetrics hermesMetrics; private final MeterRegistry meterRegistry; - OffsetCommitsMetrics(HermesMetrics hermesMetrics, MeterRegistry meterRegistry) { - this.hermesMetrics = hermesMetrics; + OffsetCommitsMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; } public HermesCounter skippedCounter() { return HermesCounters.from( - meterRegistry.counter("offset-commits.skipped"), - hermesMetrics.counter("offset-committer.skipped") + meterRegistry.counter("offset-commits.skipped") ); } public HermesCounter obsoleteCounter() { return HermesCounters.from( - meterRegistry.counter("offset-commits.obsolete"), - hermesMetrics.counter("offset-committer.obsolete") + meterRegistry.counter("offset-commits.obsolete") ); } public HermesCounter committedCounter() { return HermesCounters.from( - meterRegistry.counter("offset-commits.committed"), - hermesMetrics.counter("offset-committer.committed") + meterRegistry.counter("offset-commits.committed") ); } public HermesTimer duration() { return HermesTimer.from( - meterRegistry.timer("offset-commits.duration"), - hermesMetrics.timer("offset-committer.duration") + meterRegistry.timer("offset-commits.duration") ); } public HermesCounter failuresCounter() { return HermesCounters.from( - meterRegistry.counter("offset-commits.failures"), - hermesMetrics.counter("offset-committer.failed") + meterRegistry.counter("offset-commits.failures") ); } } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/PersistentBufferMetrics.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/PersistentBufferMetrics.java index b67c522807..798e3f57fd 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/PersistentBufferMetrics.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/PersistentBufferMetrics.java @@ -8,15 +8,12 @@ public class PersistentBufferMetrics { private final MeterRegistry meterRegistry; - private final HermesMetrics hermesMetrics; - public PersistentBufferMetrics(HermesMetrics hermesMetrics, MeterRegistry meterRegistry) { + public PersistentBufferMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; - this.hermesMetrics = hermesMetrics; } public void registerBackupStorageSizeGauge(T obj, ToDoubleFunction f) { - hermesMetrics.registerMessageRepositorySizeGauge(() -> (int) f.applyAsDouble(obj)); meterRegistry.gauge(BACKUP_STORAGE_SIZE, obj, f); } } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/ProducerMetrics.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/ProducerMetrics.java index 42f95521e6..0c1b65b913 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/ProducerMetrics.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/ProducerMetrics.java @@ -9,14 +9,12 @@ import static pl.allegro.tech.hermes.common.metric.Gauges.INFLIGHT_REQUESTS; public class ProducerMetrics { - private final HermesMetrics hermesMetrics; private final MeterRegistry meterRegistry; private final GaugeRegistrar gaugeRegistrar; - public ProducerMetrics(HermesMetrics hermesMetrics, MeterRegistry meterRegistry) { - this.hermesMetrics = hermesMetrics; + public ProducerMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; - this.gaugeRegistrar = new GaugeRegistrar(meterRegistry, hermesMetrics); + this.gaugeRegistrar = new GaugeRegistrar(meterRegistry); } public void registerAckAllTotalBytesGauge(T stateObj, ToDoubleFunction f, String sender, String datacenter) { @@ -52,20 +50,19 @@ public void registerAckLeaderFailedBatchesGauge(T stateObj, ToDoubleFunction } public void registerAckAllMetadataAgeGauge(T stateObj, ToDoubleFunction f, String sender, String datacenter) { - registerTimeGauge(stateObj, f, ACK_ALL_METADATA_AGE, ACK_ALL_METADATA_AGE, tags(sender, datacenter), TimeUnit.SECONDS); + registerTimeGauge(stateObj, f, ACK_ALL_METADATA_AGE, tags(sender, datacenter), TimeUnit.SECONDS); } public void registerAckLeaderMetadataAgeGauge(T stateObj, ToDoubleFunction f, String sender, String datacenter) { - registerTimeGauge(stateObj, f, ACK_LEADER_METADATA_AGE, ACK_LEADER_METADATA_AGE, tags(sender, datacenter), TimeUnit.SECONDS); + registerTimeGauge(stateObj, f, ACK_LEADER_METADATA_AGE, tags(sender, datacenter), TimeUnit.SECONDS); } public void registerAckAllRecordQueueTimeMaxGauge(T stateObj, ToDoubleFunction f, String sender, String datacenter) { - registerTimeGauge(stateObj, f, ACK_ALL_RECORD_QUEUE_TIME_MAX, ACK_ALL_RECORD_QUEUE_TIME_MAX, tags(sender, datacenter), TimeUnit.MILLISECONDS); + registerTimeGauge(stateObj, f, ACK_ALL_RECORD_QUEUE_TIME_MAX, tags(sender, datacenter), TimeUnit.MILLISECONDS); } public void registerAckLeaderRecordQueueTimeMaxGauge(T stateObj, ToDoubleFunction f, String sender, String datacenter) { - registerTimeGauge(stateObj, f, ACK_LEADER_RECORD_QUEUE_TIME_MAX, - ACK_LEADER_RECORD_QUEUE_TIME_MAX, tags(sender, datacenter), TimeUnit.MILLISECONDS); + registerTimeGauge(stateObj, f, ACK_LEADER_RECORD_QUEUE_TIME_MAX, tags(sender, datacenter), TimeUnit.MILLISECONDS); } public double getBufferTotalBytes() { @@ -88,7 +85,6 @@ public void registerAckAllRecordSendCounter(T stateObj, ToDoubleFunction public void registerProducerInflightRequestGauge(T stateObj, ToDoubleFunction f) { meterRegistry.gauge(INFLIGHT_REQUESTS, stateObj, f); - hermesMetrics.registerProducerInflightRequest(() -> (int) f.applyAsDouble(stateObj)); } private static Tags tags(String sender, String datacenter) { @@ -98,12 +94,10 @@ private static Tags tags(String sender, String datacenter) { private void registerTimeGauge(T stateObj, ToDoubleFunction f, - String graphiteName, - String prometheusName, + String name, Tags tags, TimeUnit timeUnit) { - hermesMetrics.registerGauge(graphiteName, () -> f.applyAsDouble(stateObj)); - meterRegistry.more().timeGauge(prometheusName, tags, stateObj, timeUnit, f); + meterRegistry.more().timeGauge(name, tags, stateObj, timeUnit, f); } private void registerCounter(String name, Tags tags, T stateObj, ToDoubleFunction f) { diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/SchemaClientMetrics.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/SchemaClientMetrics.java index a32f1d6910..020bffcc83 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/SchemaClientMetrics.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/SchemaClientMetrics.java @@ -5,29 +5,22 @@ import io.micrometer.core.instrument.Timer; import pl.allegro.tech.hermes.metrics.HermesTimer; -import static pl.allegro.tech.hermes.common.metric.Timers.GET_SCHEMA_LATENCY; -import static pl.allegro.tech.hermes.common.metric.Timers.GET_SCHEMA_VERSIONS_LATENCY; - public class SchemaClientMetrics { - private final HermesMetrics hermesMetrics; private final MeterRegistry meterRegistry; - public SchemaClientMetrics(HermesMetrics hermesMetrics, MeterRegistry meterRegistry) { - this.hermesMetrics = hermesMetrics; + public SchemaClientMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; } public HermesTimer schemaTimer() { return HermesTimer.from( - timer("schema.get-schema"), - hermesMetrics.schemaTimer(GET_SCHEMA_LATENCY) + timer("schema.get-schema") ); } public HermesTimer versionsTimer() { return HermesTimer.from( - timer("schema.get-versions"), - hermesMetrics.schemaTimer(GET_SCHEMA_VERSIONS_LATENCY) + timer("schema.get-versions") ); } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/SubscriptionHermesCounter.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/SubscriptionHermesCounter.java index 73da4f18f1..2d9d237b5a 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/SubscriptionHermesCounter.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/SubscriptionHermesCounter.java @@ -1,31 +1,23 @@ package pl.allegro.tech.hermes.common.metric; -import com.codahale.metrics.Meter; import io.micrometer.core.instrument.Counter; import pl.allegro.tech.hermes.api.SubscriptionName; -import pl.allegro.tech.hermes.metrics.counters.MeterBackedHermesCounter; +import pl.allegro.tech.hermes.metrics.counters.DefaultHermesCounter; -public class SubscriptionHermesCounter extends MeterBackedHermesCounter { +public class SubscriptionHermesCounter extends DefaultHermesCounter { - private final String graphiteName; private final SubscriptionName subscription; private SubscriptionHermesCounter(Counter micrometerCounter, - Meter graphiteMeter, - String graphiteName, SubscriptionName subscription) { - super(micrometerCounter, graphiteMeter); - this.graphiteName = graphiteName; + SubscriptionName subscription) { + super(micrometerCounter); this.subscription = subscription; } - public static SubscriptionHermesCounter from(Counter micrometerCounter, Meter graphiteMeter, - String graphiteName, SubscriptionName subscription) { - return new SubscriptionHermesCounter(micrometerCounter, graphiteMeter, graphiteName, subscription); + public static SubscriptionHermesCounter from(Counter micrometerCounter, SubscriptionName subscription) { + return new SubscriptionHermesCounter(micrometerCounter, subscription); } - String getGraphiteName() { - return graphiteName; - } SubscriptionName getSubscription() { return subscription; diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/SubscriptionMetrics.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/SubscriptionMetrics.java index 4f4916bc05..95a1b85369 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/SubscriptionMetrics.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/SubscriptionMetrics.java @@ -15,130 +15,94 @@ import static pl.allegro.tech.hermes.common.metric.SubscriptionTagsFactory.subscriptionTags; public class SubscriptionMetrics { - private final HermesMetrics hermesMetrics; private final MeterRegistry meterRegistry; - public SubscriptionMetrics(HermesMetrics hermesMetrics, MeterRegistry meterRegistry) { - this.hermesMetrics = hermesMetrics; + public SubscriptionMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; } public SubscriptionHermesCounter throughputInBytes(SubscriptionName subscription) { return SubscriptionHermesCounter.from( - micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_THROUGHPUT, subscription), - hermesMetrics.meter(Meters.SUBSCRIPTION_THROUGHPUT_BYTES, subscription.getTopicName(), subscription.getName()), - Meters.SUBSCRIPTION_THROUGHPUT_BYTES, subscription); + micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_THROUGHPUT, subscription), subscription); } public HermesCounter successes(SubscriptionName subscription) { - return size -> { - hermesMetrics.meter(Meters.METER).mark(size); - hermesMetrics.meter(Meters.TOPIC_METER, subscription.getTopicName()).mark(size); - hermesMetrics.meter(Meters.SUBSCRIPTION_METER, subscription.getTopicName(), subscription.getName()).mark(size); - hermesMetrics.counter(Counters.DELIVERED, subscription.getTopicName(), subscription.getName()).inc(size); - micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_DELIVERED, subscription).increment(size); - }; + return size -> micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_DELIVERED, subscription).increment(size); } public HermesCounter batchSuccesses(SubscriptionName subscription) { return HermesCounters.from( - micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_BATCHES, subscription), - hermesMetrics.meter(Meters.SUBSCRIPTION_BATCH_METER, subscription.getTopicName(), subscription.getName()) + micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_BATCHES, subscription) ); } public HermesCounter discarded(SubscriptionName subscription) { - return size -> { - hermesMetrics.meter(Meters.DISCARDED_METER).mark(size); - hermesMetrics.meter(Meters.DISCARDED_TOPIC_METER, subscription.getTopicName()).mark(size); - hermesMetrics.meter(Meters.DISCARDED_SUBSCRIPTION_METER, subscription.getTopicName(), subscription.getName()).mark(size); - hermesMetrics.counter(Counters.DISCARDED, subscription.getTopicName(), subscription.getName()).inc(size); - micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_DISCARDED, subscription).increment(size); - }; + return size -> micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_DISCARDED, subscription).increment(size); + } public HermesCounter retries(SubscriptionName subscription) { - return size -> { - hermesMetrics.meter(Meters.RETRIES_METER).mark(size); - hermesMetrics.meter(Meters.RETRIES_TOPIC_METER, subscription.getTopicName()).mark(size); - hermesMetrics.meter(Meters.RETRIES_SUBSCRIPTION_METER, subscription.getTopicName(), subscription.getName()).mark(size); - hermesMetrics.counter(Counters.RETRIES, subscription.getTopicName(), subscription.getName()).inc(size); - micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_RETRIES, subscription).increment(size); - }; + return size -> micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_RETRIES, subscription).increment(size); } public HermesTimer latency(SubscriptionName subscription) { return HermesTimer.from( - meterRegistry.timer(SubscriptionMetricsNames.SUBSCRIPTION_LATENCY, subscriptionTags(subscription)), - hermesMetrics.timer(Timers.SUBSCRIPTION_LATENCY, subscription.getTopicName(), subscription.getName()) + meterRegistry.timer(SubscriptionMetricsNames.SUBSCRIPTION_LATENCY, subscriptionTags(subscription)) ); } public HermesTimer rateLimiterAcquire(SubscriptionName subscription) { return HermesTimer.from( - meterRegistry.timer(SubscriptionMetricsNames.SUBSCRIPTION_RATE_LIMITER_ACQUIRE, subscriptionTags(subscription)), - hermesMetrics.timer(Timers.RATE_LIMITER_ACQUIRE, subscription.getTopicName(), subscription.getName()) + meterRegistry.timer(SubscriptionMetricsNames.SUBSCRIPTION_RATE_LIMITER_ACQUIRE, subscriptionTags(subscription)) ); } public void registerInflightGauge(SubscriptionName subscription, T obj, ToDoubleFunction f) { - hermesMetrics.registerInflightGauge(subscription, () -> (int) f.applyAsDouble(obj)); meterRegistry.gauge(SubscriptionMetricsNames.SUBSCRIPTION_INFLIGHT, subscriptionTags(subscription), obj, f); } public HermesTimer consumerIdleTimer(SubscriptionName subscription) { return HermesTimer.from( - meterRegistry.timer(SubscriptionMetricsNames.SUBSCRIPTION_IDLE_DURATION, subscriptionTags(subscription)), - hermesMetrics.timer(Timers.CONSUMER_IDLE_TIME, subscription.getTopicName(), subscription.getName()) + meterRegistry.timer(SubscriptionMetricsNames.SUBSCRIPTION_IDLE_DURATION, subscriptionTags(subscription)) ); } public HermesCounter filteredOutCounter(SubscriptionName subscription) { return HermesCounters.from( - micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_FILTERED_OUT, subscription), - hermesMetrics.meter(Meters.FILTERED_METER, subscription.getTopicName(), subscription.getName()) + micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_FILTERED_OUT, subscription) ); } public HermesCounter httpAnswerCounter(SubscriptionName subscription, int statusCode) { - return size -> { - meterRegistry.counter( - SubscriptionMetricsNames.SUBSCRIPTION_HTTP_STATUS_CODES, - Tags.concat(subscriptionTags(subscription), "status_code", String.valueOf(statusCode)) - ).increment(size); - hermesMetrics.registerConsumerHttpAnswer(subscription, statusCode, size); - }; + return size -> meterRegistry.counter( + SubscriptionMetricsNames.SUBSCRIPTION_HTTP_STATUS_CODES, + Tags.concat(subscriptionTags(subscription), "status_code", String.valueOf(statusCode)) + ).increment(size); } public HermesCounter timeoutsCounter(SubscriptionName subscription) { return HermesCounters.from( - micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_TIMEOUTS, subscription), - hermesMetrics.consumerErrorsTimeoutMeter(subscription) + micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_TIMEOUTS, subscription) ); } public HermesCounter otherErrorsCounter(SubscriptionName subscription) { return HermesCounters.from( - micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_OTHER_ERRORS, subscription), - hermesMetrics.consumerErrorsOtherMeter(subscription) + micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_OTHER_ERRORS, subscription) ); } public HermesCounter failuresCounter(SubscriptionName subscription) { return HermesCounters.from( - micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_FAILURES, subscription), - hermesMetrics.meter(Meters.FAILED_METER_SUBSCRIPTION, subscription.getTopicName(), subscription.getName()) + micrometerCounter(SubscriptionMetricsNames.SUBSCRIPTION_FAILURES, subscription) ); } public HermesHistogram inflightTimeInMillisHistogram(SubscriptionName subscriptionName) { - return value -> { - DistributionSummary.builder(SubscriptionMetricsNames.SUBSCRIPTION_INFLIGHT_TIME) - .tags(subscriptionTags(subscriptionName)) - .register(meterRegistry) - .record(value / 1000d); - hermesMetrics.inflightTimeHistogram(subscriptionName).update(value); - }; + return value -> DistributionSummary.builder(SubscriptionMetricsNames.SUBSCRIPTION_INFLIGHT_TIME) + .tags(subscriptionTags(subscriptionName)) + .register(meterRegistry) + .record(value / 1000d); } private Counter micrometerCounter(String metricName, SubscriptionName subscription) { diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Timers.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Timers.java deleted file mode 100644 index f130b21410..0000000000 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/Timers.java +++ /dev/null @@ -1,33 +0,0 @@ -package pl.allegro.tech.hermes.common.metric; - -import static pl.allegro.tech.hermes.metrics.PathsCompiler.GROUP; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.KAFKA_CLUSTER; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.OAUTH_PROVIDER_NAME; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.SCHEMA_REPO_TYPE; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.SUBSCRIPTION; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.TOPIC; - -public class Timers { - - public static final String ACK_ALL_BROKER_LATENCY = "ack-all.broker-latency"; - public static final String ACK_LEADER_BROKER_LATENCY = "ack-leader.broker-latency"; - - public static final String ACK_ALL_LATENCY = "ack-all.latency"; - public static final String ACK_ALL_TOPIC_LATENCY = ACK_ALL_LATENCY + "." + GROUP + "." + TOPIC; - - public static final String ACK_LEADER_LATENCY = "ack-leader.latency"; - public static final String ACK_LEADER_TOPIC_LATENCY = ACK_LEADER_LATENCY + "." + GROUP + "." + TOPIC; - - public static final String LATENCY = "latency"; - public static final String SUBSCRIPTION_LATENCY = LATENCY + "." + GROUP + "." + TOPIC + "." + SUBSCRIPTION; - public static final String RATE_LIMITER_ACQUIRE = "rate-limiter-acquire" + "." + GROUP + "." + TOPIC + "." + SUBSCRIPTION; - - public static final String SCHEMA = "schema." + SCHEMA_REPO_TYPE; - public static final String GET_SCHEMA_LATENCY = SCHEMA + ".get-schema"; - public static final String GET_SCHEMA_VERSIONS_LATENCY = SCHEMA + ".get-schema-versions"; - - public static final String CONSUMER_WORKLOAD_REBALANCE_DURATION = "consumers-workload." + KAFKA_CLUSTER + ".rebalance-duration"; - public static final String CONSUMER_IDLE_TIME = "idle-time." + GROUP + "." + TOPIC + "." + SUBSCRIPTION; - - public static final String OAUTH_PROVIDER_TOKEN_REQUEST_LATENCY = "oauth.provider." + OAUTH_PROVIDER_NAME + ".token-request-latency"; -} diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/TopicMetrics.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/TopicMetrics.java index bab7b92e01..e7ae1dcf89 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/TopicMetrics.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/TopicMetrics.java @@ -12,132 +12,110 @@ import pl.allegro.tech.hermes.metrics.HermesHistogram; import pl.allegro.tech.hermes.metrics.HermesTimer; import pl.allegro.tech.hermes.metrics.counters.HermesCounters; -import pl.allegro.tech.hermes.metrics.counters.MeterBackedHermesCounter; - -import static pl.allegro.tech.hermes.common.metric.Meters.DELAYED_PROCESSING; public class TopicMetrics { - private final HermesMetrics hermesMetrics; private final MeterRegistry meterRegistry; - public TopicMetrics(HermesMetrics hermesMetrics, MeterRegistry meterRegistry) { - this.hermesMetrics = hermesMetrics; + public TopicMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; } public HermesTimer ackAllGlobalLatency() { return HermesTimer.from( - meterRegistry.timer(TopicMetricsNames.TOPIC_ACK_ALL_GLOBAL_LATENCY), - hermesMetrics.timer(Timers.ACK_ALL_LATENCY) + meterRegistry.timer(TopicMetricsNames.TOPIC_ACK_ALL_GLOBAL_LATENCY) ); } public HermesTimer ackAllTopicLatency(TopicName topic) { return HermesTimer.from( - micrometerTimer(TopicMetricsNames.TOPIC_ACK_ALL_LATENCY, topic), - hermesMetrics.timer(Timers.ACK_ALL_TOPIC_LATENCY, topic)); + micrometerTimer(TopicMetricsNames.TOPIC_ACK_ALL_LATENCY, topic)); } public HermesTimer ackAllBrokerLatency() { return HermesTimer.from( - meterRegistry.timer(TopicMetricsNames.TOPIC_ACK_ALL_BROKER_LATENCY), - hermesMetrics.timer(Timers.ACK_ALL_BROKER_LATENCY)); + meterRegistry.timer(TopicMetricsNames.TOPIC_ACK_ALL_BROKER_LATENCY)); } public HermesTimer ackLeaderGlobalLatency() { return HermesTimer.from( - meterRegistry.timer(TopicMetricsNames.TOPIC_ACK_LEADER_GLOBAL_LATENCY), - hermesMetrics.timer(Timers.ACK_LEADER_LATENCY)); + meterRegistry.timer(TopicMetricsNames.TOPIC_ACK_LEADER_GLOBAL_LATENCY)); } public HermesTimer ackLeaderTopicLatency(TopicName topic) { return HermesTimer.from( - micrometerTimer(TopicMetricsNames.TOPIC_ACK_LEADER_LATENCY, topic), - hermesMetrics.timer(Timers.ACK_LEADER_TOPIC_LATENCY, topic)); + micrometerTimer(TopicMetricsNames.TOPIC_ACK_LEADER_LATENCY, topic)); } public HermesTimer ackLeaderBrokerLatency() { return HermesTimer.from( - meterRegistry.timer(TopicMetricsNames.TOPIC_ACK_LEADER_BROKER_LATENCY), - hermesMetrics.timer(Timers.ACK_LEADER_BROKER_LATENCY)); + meterRegistry.timer(TopicMetricsNames.TOPIC_ACK_LEADER_BROKER_LATENCY)); } - public MeterBackedHermesCounter topicThroughputBytes(TopicName topicName) { + public HermesCounter topicThroughputBytes(TopicName topicName) { return HermesCounters.from( - micrometerCounter(TopicMetricsNames.TOPIC_THROUGHPUT, topicName), - hermesMetrics.meter(Meters.TOPIC_THROUGHPUT_BYTES, topicName) + micrometerCounter(TopicMetricsNames.TOPIC_THROUGHPUT, topicName) ); } - public MeterBackedHermesCounter topicGlobalThroughputBytes() { + public HermesCounter topicGlobalThroughputBytes() { return HermesCounters.from( - meterRegistry.counter(TopicMetricsNames.TOPIC_GLOBAL_THROUGHPUT), - hermesMetrics.meter(Meters.THROUGHPUT_BYTES) + meterRegistry.counter(TopicMetricsNames.TOPIC_GLOBAL_THROUGHPUT) ); } public HermesCounter topicPublished(TopicName topicName, String datacenter) { return HermesCounters.from( - micrometerCounter(TopicMetricsNames.TOPIC_PUBLISHED, topicName, Tag.of("storageDc", datacenter)), - hermesMetrics.counter(Counters.PUBLISHED, topicName) + micrometerCounter(TopicMetricsNames.TOPIC_PUBLISHED, topicName, Tag.of("storageDc", datacenter)) ); } public HermesCounter topicGlobalRequestCounter() { return HermesCounters.from( - meterRegistry.counter(TopicMetricsNames.TOPIC_GLOBAL_REQUESTS), - hermesMetrics.meter(Meters.METER) + meterRegistry.counter(TopicMetricsNames.TOPIC_GLOBAL_REQUESTS) ); } public HermesCounter topicRequestCounter(TopicName topicName) { return HermesCounters.from( - micrometerCounter(TopicMetricsNames.TOPIC_REQUESTS, topicName), - hermesMetrics.meter(Meters.TOPIC_METER, topicName) + micrometerCounter(TopicMetricsNames.TOPIC_REQUESTS, topicName) ); } public HermesCounter topicGlobalDelayedProcessingCounter() { return HermesCounters.from( - meterRegistry.counter(TopicMetricsNames.TOPIC_GLOBAL_DELAYED_PROCESSING), - hermesMetrics.meter(DELAYED_PROCESSING) + meterRegistry.counter(TopicMetricsNames.TOPIC_GLOBAL_DELAYED_PROCESSING) ); } public HermesCounter topicDelayedProcessingCounter(TopicName topicName) { return HermesCounters.from( - micrometerCounter(TopicMetricsNames.TOPIC_DELAYED_PROCESSING, topicName), - hermesMetrics.meter(Meters.TOPIC_DELAYED_PROCESSING, topicName) + micrometerCounter(TopicMetricsNames.TOPIC_DELAYED_PROCESSING, topicName) ); } public HermesCounter topicGlobalHttpStatusCodeCounter(int statusCode) { return HermesCounters.from( - meterRegistry.counter(TopicMetricsNames.TOPIC_GLOBAL_HTTP_STATUS_CODES, Tags.of("status_code", String.valueOf(statusCode))), - hermesMetrics.httpStatusCodeMeter(statusCode) + meterRegistry.counter(TopicMetricsNames.TOPIC_GLOBAL_HTTP_STATUS_CODES, Tags.of("status_code", String.valueOf(statusCode))) ); } public HermesCounter topicHttpStatusCodeCounter(TopicName topicName, int statusCode) { return HermesCounters.from( meterRegistry.counter(TopicMetricsNames.TOPIC_HTTP_STATUS_CODES, topicTags(topicName) - .and("status_code", String.valueOf(statusCode))), - hermesMetrics.httpStatusCodeMeter(statusCode, topicName) + .and("status_code", String.valueOf(statusCode))) ); } public HermesCounter topicDuplicatedMessageCounter(TopicName topicName) { return HermesCounters.from( - micrometerCounter(TopicMetricsNames.TOPIC_DUPLICATED_MESSAGE, topicName), - hermesMetrics.meter(Meters.TOPIC_DUPLICATED_MESSAGE, topicName) + micrometerCounter(TopicMetricsNames.TOPIC_DUPLICATED_MESSAGE, topicName) ); } public HermesHistogram topicGlobalMessageContentSizeHistogram() { return DefaultHermesHistogram.of( DistributionSummary.builder(TopicMetricsNames.TOPIC_GLOBAL_MESSAGE_SIZE_BYTES) - .register(meterRegistry), - hermesMetrics.messageContentSizeHistogram() + .register(meterRegistry) ); } @@ -145,8 +123,7 @@ public HermesHistogram topicMessageContentSizeHistogram(TopicName topicName) { return DefaultHermesHistogram.of( DistributionSummary.builder(TopicMetricsNames.TOPIC_MESSAGE_SIZE_BYTES) .tags(topicTags(topicName)) - .register(meterRegistry), - hermesMetrics.messageContentSizeHistogram(topicName) + .register(meterRegistry) ); } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/TrackerElasticSearchMetrics.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/TrackerElasticSearchMetrics.java index b9643f5a30..657fb68c1e 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/TrackerElasticSearchMetrics.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/TrackerElasticSearchMetrics.java @@ -5,75 +5,52 @@ import java.util.function.ToDoubleFunction; -import static pl.allegro.tech.hermes.metrics.PathsCompiler.HOSTNAME; - public class TrackerElasticSearchMetrics { private final MeterRegistry meterRegistry; - private final HermesMetrics hermesMetrics; private final GaugeRegistrar gaugeRegistrar; - public TrackerElasticSearchMetrics(HermesMetrics hermesMetrics, MeterRegistry meterRegistry) { + public TrackerElasticSearchMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; - this.hermesMetrics = hermesMetrics; - this.gaugeRegistrar = new GaugeRegistrar(meterRegistry, hermesMetrics); + this.gaugeRegistrar = new GaugeRegistrar(meterRegistry); } public void registerProducerTrackerElasticSearchQueueSizeGauge(T stateObj, ToDoubleFunction f) { gaugeRegistrar.registerGauge( - Gauges.Graphite.PRODUCER_TRACKER_ELASTICSEARCH_QUEUE_SIZE, - Gauges.Prometheus.TRACKER_ELASTICSEARCH_QUEUE_SIZE, + Gauges.TRACKER_ELASTICSEARCH_QUEUE_SIZE, stateObj, f ); } public void registerProducerTrackerElasticSearchRemainingCapacity(T stateObj, ToDoubleFunction f) { gaugeRegistrar.registerGauge( - Gauges.Graphite.PRODUCER_TRACKER_ELASTICSEARCH_REMAINING_CAPACITY, - Gauges.Prometheus.TRACKER_ELASTICSEARCH_REMAINING_CAPACITY, + Gauges.TRACKER_ELASTICSEARCH_REMAINING_CAPACITY, stateObj, f ); } public void registerConsumerTrackerElasticSearchQueueSizeGauge(T stateObj, ToDoubleFunction f) { gaugeRegistrar.registerGauge( - Gauges.Graphite.CONSUMER_TRACKER_ELASTICSEARCH_QUEUE_SIZE, - Gauges.Prometheus.TRACKER_ELASTICSEARCH_QUEUE_SIZE, + Gauges.TRACKER_ELASTICSEARCH_QUEUE_SIZE, stateObj, f ); } public void registerConsumerTrackerElasticSearchRemainingCapacity(T stateObj, ToDoubleFunction f) { gaugeRegistrar.registerGauge( - Gauges.Graphite.CONSUMER_TRACKER_ELASTICSEARCH_REMAINING_CAPACITY, - Gauges.Prometheus.TRACKER_ELASTICSEARCH_REMAINING_CAPACITY, + Gauges.TRACKER_ELASTICSEARCH_REMAINING_CAPACITY, stateObj, f ); } public HermesTimer trackerElasticSearchCommitLatencyTimer() { return HermesTimer.from( - meterRegistry.timer(Timers.ELASTICSEARCH_COMMIT_LATENCY), - hermesMetrics.timer(Timers.ELASTICSEARCH_COMMIT_LATENCY) + meterRegistry.timer(Timers.ELASTICSEARCH_COMMIT_LATENCY) ); } private static class Gauges { - private static class Graphite { - public static final String PRODUCER_TRACKER_ELASTICSEARCH_QUEUE_SIZE = - "producer." + HOSTNAME + ".tracker.elasticsearch.queue-size"; - public static final String PRODUCER_TRACKER_ELASTICSEARCH_REMAINING_CAPACITY = - "producer." + HOSTNAME + ".tracker.elasticsearch.remaining-capacity"; - - public static final String CONSUMER_TRACKER_ELASTICSEARCH_QUEUE_SIZE = - "consumer." + HOSTNAME + ".tracker.elasticsearch.queue-size"; - public static final String CONSUMER_TRACKER_ELASTICSEARCH_REMAINING_CAPACITY = - "consumer." + HOSTNAME + ".tracker.elasticsearch.remaining-capacity"; - } - - private static class Prometheus { - public static final String TRACKER_ELASTICSEARCH_QUEUE_SIZE = "tracker.elasticsearch.queue-size"; - public static final String TRACKER_ELASTICSEARCH_REMAINING_CAPACITY = "tracker.elasticsearch.remaining-capacity"; - } + public static final String TRACKER_ELASTICSEARCH_QUEUE_SIZE = "tracker.elasticsearch.queue-size"; + public static final String TRACKER_ELASTICSEARCH_REMAINING_CAPACITY = "tracker.elasticsearch.remaining-capacity"; } private static class Timers { diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/UndeliveredMessagesMetrics.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/UndeliveredMessagesMetrics.java index ca4edaa24e..3a286a0bf3 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/UndeliveredMessagesMetrics.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/UndeliveredMessagesMetrics.java @@ -7,30 +7,23 @@ import pl.allegro.tech.hermes.metrics.HermesHistogram; import pl.allegro.tech.hermes.metrics.counters.HermesCounters; -import static pl.allegro.tech.hermes.common.metric.Histograms.PERSISTED_UNDELIVERED_MESSAGE_SIZE; -import static pl.allegro.tech.hermes.common.metric.Meters.PERSISTED_UNDELIVERED_MESSAGES_METER; - public class UndeliveredMessagesMetrics { - private final HermesMetrics hermesMetrics; private final MeterRegistry meterRegistry; - public UndeliveredMessagesMetrics(HermesMetrics hermesMetrics, MeterRegistry meterRegistry) { - this.hermesMetrics = hermesMetrics; + public UndeliveredMessagesMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; } public HermesCounter undeliveredMessagesCounter() { return HermesCounters.from( - meterRegistry.counter("undelivered-messages.persisted"), - hermesMetrics.meter(PERSISTED_UNDELIVERED_MESSAGES_METER) + meterRegistry.counter("undelivered-messages.persisted") ); } public HermesHistogram undeliveredMessagesSizeHistogram() { return DefaultHermesHistogram.of( DistributionSummary.builder("undelivered-messages.persisted.message-size.bytes") - .register(meterRegistry), - hermesMetrics.histogram(PERSISTED_UNDELIVERED_MESSAGE_SIZE) + .register(meterRegistry) ); } } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/WorkloadMetrics.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/WorkloadMetrics.java index 7c2e840d0f..1faa3486c3 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/WorkloadMetrics.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/WorkloadMetrics.java @@ -14,27 +14,17 @@ public class WorkloadMetrics { private static final String CONSUMER_ID_TAG = "consumer-id"; private static final String KAFKA_CLUSTER_TAG = "kafka-cluster"; - private static final String METRICS_PREFIX = "consumer-workload.weighted."; - private static final String CONSUMER_ID_PLACEHOLDER = "$consumerId"; - private static final String CURRENT_SCORE = METRICS_PREFIX + CONSUMER_ID_PLACEHOLDER + ".current-score"; - private static final String PROPOSED_SCORE = METRICS_PREFIX + CONSUMER_ID_PLACEHOLDER + ".proposed-score"; - private static final String SCORING_ERROR = METRICS_PREFIX + CONSUMER_ID_PLACEHOLDER + ".error"; - private static final String CURRENT_WEIGHT_OPS = METRICS_PREFIX + CONSUMER_ID_PLACEHOLDER + ".current-weight.ops"; - private static final String PROPOSED_WEIGHT_OPS = METRICS_PREFIX + CONSUMER_ID_PLACEHOLDER + ".proposed-weight.ops"; - - private final HermesMetrics hermesMetrics; + private final MeterRegistry meterRegistry; private final GaugeRegistrar gaugeRegistrar; - WorkloadMetrics(HermesMetrics hermesMetrics, MeterRegistry meterRegistry) { - this.hermesMetrics = hermesMetrics; + WorkloadMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; - this.gaugeRegistrar = new GaugeRegistrar(meterRegistry, hermesMetrics); + this.gaugeRegistrar = new GaugeRegistrar(meterRegistry); } public void registerAllAssignmentsGauge(T obj, String kafkaCluster, ToDoubleFunction f) { gaugeRegistrar.registerGauge( - "consumers-workload." + kafkaCluster + ".all-assignments", "workload.all-assignments", obj, f, @@ -44,7 +34,6 @@ public void registerAllAssignmentsGauge(T obj, String kafkaCluster, ToDouble public void registerMissingResourcesGauge(T obj, String kafkaCluster, ToDoubleFunction f) { gaugeRegistrar.registerGauge( - "consumers-workload." + kafkaCluster + ".missing-resources", "workload.missing-resources", obj, f, @@ -54,7 +43,6 @@ public void registerMissingResourcesGauge(T obj, String kafkaCluster, ToDoub public void registerDeletedAssignmentsGauge(T obj, String kafkaCluster, ToDoubleFunction f) { gaugeRegistrar.registerGauge( - "consumers-workload." + kafkaCluster + ".deleted-assignments", "workload.deleted-assignments", obj, f, @@ -64,7 +52,6 @@ public void registerDeletedAssignmentsGauge(T obj, String kafkaCluster, ToDo public void registerCreatedAssignmentsGauge(T obj, String kafkaCluster, ToDoubleFunction f) { gaugeRegistrar.registerGauge( - "consumers-workload." + kafkaCluster + ".created-assignments", "workload.created-assignments", obj, f, @@ -74,38 +61,36 @@ public void registerCreatedAssignmentsGauge(T obj, String kafkaCluster, ToDo public HermesTimer rebalanceDurationTimer(String kafkaCluster) { return HermesTimer.from( - meterRegistry.timer("workload.rebalance-duration", Tags.of(KAFKA_CLUSTER_TAG, kafkaCluster)), - hermesMetrics.consumersWorkloadRebalanceDurationTimer(kafkaCluster) + meterRegistry.timer("workload.rebalance-duration", Tags.of(KAFKA_CLUSTER_TAG, kafkaCluster)) ); } public void registerRunningSubscriptionsGauge(T obj, ToDoubleFunction f) { - gaugeRegistrar.registerGauge("consumers-workload.monitor.running", "workload.subscriptions.running", obj, f); + gaugeRegistrar.registerGauge("workload.subscriptions.running", obj, f); } public void registerAssignedSubscriptionsGauge(T obj, ToDoubleFunction f) { - gaugeRegistrar.registerGauge("consumers-workload.monitor.assigned", "workload.subscriptions.assigned", obj, f); + gaugeRegistrar.registerGauge("workload.subscriptions.assigned", obj, f); } public void registerMissingSubscriptionsGauge(T obj, ToDoubleFunction f) { - gaugeRegistrar.registerGauge("consumers-workload.monitor.missing", "workload.subscriptions.missing", obj, f); + gaugeRegistrar.registerGauge("workload.subscriptions.missing", obj, f); } public void registerOversubscribedGauge(T obj, ToDoubleFunction f) { - gaugeRegistrar.registerGauge("consumers-workload.monitor.oversubscribed", "workload.subscriptions.oversubscribed", obj, f); + gaugeRegistrar.registerGauge("workload.subscriptions.oversubscribed", obj, f); } public void registerOperationsPerSecondGauge(T obj, ToDoubleFunction f) { - gaugeRegistrar.registerGauge("consumer-workload.weighted.load.ops", "workload.weighted.ops", obj, f); + gaugeRegistrar.registerGauge("workload.weighted.ops", obj, f); } public void registerCpuUtilizationGauge(T obj, ToDoubleFunction f) { - gaugeRegistrar.registerGauge("consumer-workload.weighted.load.cpu-utilization", "workload.weighted.cpu-utilization", obj, f); + gaugeRegistrar.registerGauge("workload.weighted.cpu-utilization", obj, f); } public void registerCurrentScoreGauge(String consumerId, T obj, ToDoubleFunction f) { gaugeRegistrar.registerGauge( - buildFullGraphiteMetricPath(CURRENT_SCORE, consumerId), "workload.weighted.current-score", obj, f, @@ -115,7 +100,6 @@ public void registerCurrentScoreGauge(String consumerId, T obj, ToDoubleFunc public void registerProposedErrorGauge(String consumerId, T obj, ToDoubleFunction f) { gaugeRegistrar.registerGauge( - buildFullGraphiteMetricPath(PROPOSED_SCORE, consumerId), "workload.weighted.proposed-error", obj, f, @@ -125,7 +109,6 @@ public void registerProposedErrorGauge(String consumerId, T obj, ToDoubleFun public void registerScoringErrorGauge(String consumerId, T obj, ToDoubleFunction f) { gaugeRegistrar.registerGauge( - buildFullGraphiteMetricPath(SCORING_ERROR, consumerId), "workload.weighted.scoring-error", obj, f, @@ -135,7 +118,6 @@ public void registerScoringErrorGauge(String consumerId, T obj, ToDoubleFunc public void registerCurrentWeightGauge(String consumerId, T obj, ToDoubleFunction f) { gaugeRegistrar.registerGauge( - buildFullGraphiteMetricPath(CURRENT_WEIGHT_OPS, consumerId), "workload.weighted.current-weight.ops", obj, f, @@ -145,7 +127,6 @@ public void registerCurrentWeightGauge(String consumerId, T obj, ToDoubleFun public void registerProposedWeightGauge(String consumerId, T obj, ToDoubleFunction f) { gaugeRegistrar.registerGauge( - buildFullGraphiteMetricPath(PROPOSED_WEIGHT_OPS, consumerId), "workload.weighted.proposed-weight.ops", obj, f, @@ -161,16 +142,5 @@ public void unregisterAllWorkloadWeightedGaugesForConsumerIds(Set consum for (Gauge gauge : gauges) { meterRegistry.remove(gauge); } - for (String consumerId : consumerIds) { - hermesMetrics.unregister(buildFullGraphiteMetricPath(CURRENT_SCORE, consumerId)); - hermesMetrics.unregister(buildFullGraphiteMetricPath(PROPOSED_SCORE, consumerId)); - hermesMetrics.unregister(buildFullGraphiteMetricPath(SCORING_ERROR, consumerId)); - hermesMetrics.unregister(buildFullGraphiteMetricPath(CURRENT_WEIGHT_OPS, consumerId)); - hermesMetrics.unregister(buildFullGraphiteMetricPath(PROPOSED_WEIGHT_OPS, consumerId)); - } - } - - private String buildFullGraphiteMetricPath(String metric, String consumerId) { - return metric.replace(CONSUMER_ID_PLACEHOLDER, HermesMetrics.escapeDots(consumerId)); } } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/counter/zookeeper/ZookeeperCounterReporter.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/counter/zookeeper/ZookeeperCounterReporter.java index c66efdc640..3293bea92b 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/counter/zookeeper/ZookeeperCounterReporter.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/counter/zookeeper/ZookeeperCounterReporter.java @@ -7,8 +7,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pl.allegro.tech.hermes.api.TopicName; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.counter.CounterStorage; +import pl.allegro.tech.hermes.metrics.PathsCompiler; import java.util.Collection; import java.util.concurrent.Executors; @@ -101,6 +101,6 @@ private static TopicName escapedTopicName(TopicName topicName) { } private static String escapeMetricsReplacementChar(String value) { - return value.replaceAll(HermesMetrics.REPLACEMENT_CHAR, "\\."); + return value.replaceAll(PathsCompiler.REPLACEMENT_CHAR, "\\."); } } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/executor/InstrumentedExecutorServiceFactory.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/executor/InstrumentedExecutorServiceFactory.java index 621876228e..08a69b7936 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/executor/InstrumentedExecutorServiceFactory.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/metric/executor/InstrumentedExecutorServiceFactory.java @@ -33,23 +33,51 @@ public ExecutorService getExecutorService(String name, int size, boolean monitor return monitoringEnabled ? monitor(name, executor) : executor; } - public ScheduledExecutorService getScheduledExecutorService( - String name, int size, boolean monitoringEnabled - ) { - ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(name + "-scheduled-executor-%d").build(); - ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(size, threadFactory); - return monitoringEnabled ? monitor(name, executor) : executor; + public class ScheduledExecutorServiceBuilder { + final String name; + final int size; + boolean monitoringEnabled = false; + boolean removeOnCancel = false; + + public ScheduledExecutorServiceBuilder(String name, int size) { + this.name = name; + this.size = size; + } + + public ScheduledExecutorServiceBuilder withMonitoringEnabled(boolean monitoringEnabled) { + this.monitoringEnabled = monitoringEnabled; + return this; + } + + public ScheduledExecutorServiceBuilder withRemoveOnCancel(boolean removeOnCancel) { + this.removeOnCancel = removeOnCancel; + return this; + } + + public ScheduledExecutorService create() { + ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(name + "-scheduled-executor-%d").build(); + ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(size, threadFactory); + executor.setRemoveOnCancelPolicy(removeOnCancel); + return monitoringEnabled ? monitor(name, executor) : executor; + } + + private ScheduledExecutorService monitor(String threadPoolName, ScheduledExecutorService executor) { + return metricsFacade.executor().monitor(executor, threadPoolName); + } } - private ExecutorService monitor(String threadPoolName, ExecutorService executor) { - return metricsFacade.executor().monitor(executor, threadPoolName); + public ScheduledExecutorServiceBuilder scheduledExecutorBuilder( + String name, int size + ) { + return new ScheduledExecutorServiceBuilder(name, size); } - private ScheduledExecutorService monitor(String threadPoolName, ScheduledExecutorService executor) { + private ExecutorService monitor(String threadPoolName, ExecutorService executor) { return metricsFacade.executor().monitor(executor, threadPoolName); } + /** * Copy of {@link java.util.concurrent.Executors#newFixedThreadPool(int, java.util.concurrent.ThreadFactory)} * with configurable queue capacity. diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/schema/RawSchemaClientFactory.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/schema/RawSchemaClientFactory.java index e4bf8933cc..028d649399 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/common/schema/RawSchemaClientFactory.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/common/schema/RawSchemaClientFactory.java @@ -1,7 +1,6 @@ package pl.allegro.tech.hermes.common.schema; import com.fasterxml.jackson.databind.ObjectMapper; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; import pl.allegro.tech.hermes.schema.RawSchemaClient; import pl.allegro.tech.hermes.schema.SubjectNamingStrategy; diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/domain/filtering/avro/AvroPathPredicate.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/domain/filtering/avro/AvroPathPredicate.java index f49a22d7ba..7cd000a2e5 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/domain/filtering/avro/AvroPathPredicate.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/domain/filtering/avro/AvroPathPredicate.java @@ -1,5 +1,6 @@ package pl.allegro.tech.hermes.domain.filtering.avro; +import jakarta.annotation.Nullable; import org.apache.avro.Schema; import org.apache.avro.generic.GenericArray; import org.apache.avro.generic.GenericRecord; @@ -26,7 +27,7 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptyListIterator; import static java.util.Collections.singletonList; -import static org.apache.commons.lang.StringUtils.strip; +import static org.apache.commons.lang3.StringUtils.strip; import static pl.allegro.tech.hermes.common.message.converter.AvroRecordToBytesConverter.bytesToRecord; import static pl.allegro.tech.hermes.domain.filtering.FilteringException.check; @@ -62,7 +63,7 @@ public boolean test(final FilterableMessage message) { } private List select(final FilterableMessage message) throws IOException { - CompiledSchema compiledSchema = message.getSchema().get(); + CompiledSchema compiledSchema = message.getSchema().get(); return select(bytesToRecord(message.getData(), compiledSchema.getSchema())); } @@ -82,7 +83,7 @@ private List select(Object record, ListIterator iter) { if (arrayMatcher.matches()) { selector = arrayMatcher.group(GROUP_SELECTOR); - current = currentRecord.get(selector); + current = recordFieldValueOrNull(selector, currentRecord); if (!(current instanceof GenericArray)) { return emptyList(); } @@ -97,7 +98,7 @@ private List select(Object record, ListIterator iter) { } } else { - current = currentRecord.get(selector); + current = recordFieldValueOrNull(selector, currentRecord); } } else if (current instanceof HashMap) { Map currentRecord = (HashMap) current; @@ -115,9 +116,9 @@ private boolean isSupportedType(Object record) { private List selectMultipleArrayItems(ListIterator iter, GenericArray currentArray) { return currentArray.stream() - .map(item -> select(item, iter.hasNext() ? path.listIterator(iter.nextIndex()) : emptyListIterator())) - .flatMap(List::stream) - .collect(Collectors.toList()); + .map(item -> select(item, iter.hasNext() ? path.listIterator(iter.nextIndex()) : emptyListIterator())) + .flatMap(List::stream) + .collect(Collectors.toList()); } private Object selectSingleArrayItem(int idx, GenericArray currentArray) { @@ -139,6 +140,15 @@ private boolean matchResultsStream(Stream results) { } } + @Nullable + private Object recordFieldValueOrNull(String selector, GenericRecord record) { + Schema.Field field = record.getSchema().getField(selector); + if (field == null) { + return null; + } + return record.get(field.pos()); + } + private boolean matches(String value) { return pattern.matcher(value).matches(); } diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperBasedRepository.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperBasedRepository.java index b688aa314d..dcb958901c 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperBasedRepository.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperBasedRepository.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang3.ArrayUtils; import org.apache.curator.framework.CuratorFramework; import org.apache.zookeeper.data.Stat; import org.slf4j.Logger; diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperPaths.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperPaths.java index b39596faca..9e04bcc64c 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperPaths.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperPaths.java @@ -1,7 +1,7 @@ package pl.allegro.tech.hermes.infrastructure.zookeeper; import com.google.common.base.Joiner; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import pl.allegro.tech.hermes.api.Subscription; import pl.allegro.tech.hermes.api.SubscriptionName; import pl.allegro.tech.hermes.api.TopicName; diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/cache/HierarchicalCacheLevel.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/cache/HierarchicalCacheLevel.java index 320a60d0a1..2e1a9795b3 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/cache/HierarchicalCacheLevel.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/cache/HierarchicalCacheLevel.java @@ -1,6 +1,6 @@ package pl.allegro.tech.hermes.infrastructure.zookeeper.cache; -import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang3.ArrayUtils; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.recipes.cache.PathChildrenCache; import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; diff --git a/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/notifications/ZookeeperInternalNotificationBus.java b/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/notifications/ZookeeperInternalNotificationBus.java index d7989ba7d0..ccab8542d7 100644 --- a/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/notifications/ZookeeperInternalNotificationBus.java +++ b/hermes-common/src/main/java/pl/allegro/tech/hermes/infrastructure/zookeeper/notifications/ZookeeperInternalNotificationBus.java @@ -1,7 +1,7 @@ package pl.allegro.tech.hermes.infrastructure.zookeeper.notifications; import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang3.ArrayUtils; import org.apache.curator.framework.recipes.cache.ChildData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/hermes-common/src/test/groovy/pl/allegro/tech/hermes/common/metric/executor/InstrumentedExecutorServiceFactoryMetricsTest.groovy b/hermes-common/src/test/groovy/pl/allegro/tech/hermes/common/metric/executor/InstrumentedExecutorServiceFactoryMetricsTest.groovy index 91d5ad69ac..7ad8cee715 100644 --- a/hermes-common/src/test/groovy/pl/allegro/tech/hermes/common/metric/executor/InstrumentedExecutorServiceFactoryMetricsTest.groovy +++ b/hermes-common/src/test/groovy/pl/allegro/tech/hermes/common/metric/executor/InstrumentedExecutorServiceFactoryMetricsTest.groovy @@ -1,12 +1,9 @@ package pl.allegro.tech.hermes.common.metric.executor -import com.codahale.metrics.MetricRegistry import io.micrometer.core.instrument.MeterRegistry import io.micrometer.core.instrument.search.Search import io.micrometer.core.instrument.simple.SimpleMeterRegistry -import pl.allegro.tech.hermes.common.metric.HermesMetrics import pl.allegro.tech.hermes.common.metric.MetricsFacade -import pl.allegro.tech.hermes.metrics.PathsCompiler import spock.lang.Specification import spock.lang.Subject @@ -25,8 +22,7 @@ class InstrumentedExecutorServiceFactoryMetricsTest extends Specification { private final InstrumentedExecutorServiceFactory factory = new InstrumentedExecutorServiceFactory( new MetricsFacade( - meterRegistry, - new HermesMetrics(new MetricRegistry(), new PathsCompiler("host")) + meterRegistry ) ) @@ -49,7 +45,8 @@ class InstrumentedExecutorServiceFactoryMetricsTest extends Specification { def "should record metrics for scheduled executor service (monitoring enabled: #monitoringEnabled)"() { given: - ScheduledExecutorService executor = factory.getScheduledExecutorService("test-scheduled-executor", 10, monitoringEnabled) + ScheduledExecutorService executor = factory.scheduledExecutorBuilder("test-scheduled-executor", 10) + .withMonitoringEnabled(monitoringEnabled).create() when: ScheduledFuture task = executor.schedule({ println("scheduled task executed") }, 1, SECONDS) diff --git a/hermes-common/src/test/groovy/pl/allegro/tech/hermes/common/schema/ReadMetricsTrackingRawSchemaClientTest.groovy b/hermes-common/src/test/groovy/pl/allegro/tech/hermes/common/schema/ReadMetricsTrackingRawSchemaClientTest.groovy index 8e8d3d4e8a..f6e128fc8a 100644 --- a/hermes-common/src/test/groovy/pl/allegro/tech/hermes/common/schema/ReadMetricsTrackingRawSchemaClientTest.groovy +++ b/hermes-common/src/test/groovy/pl/allegro/tech/hermes/common/schema/ReadMetricsTrackingRawSchemaClientTest.groovy @@ -1,16 +1,12 @@ package pl.allegro.tech.hermes.common.schema -import com.codahale.metrics.MetricRegistry import io.micrometer.core.instrument.MeterRegistry import io.micrometer.core.instrument.Timer import io.micrometer.core.instrument.search.Search import io.micrometer.core.instrument.simple.SimpleMeterRegistry import pl.allegro.tech.hermes.api.RawSchema import pl.allegro.tech.hermes.api.TopicName -import pl.allegro.tech.hermes.common.metric.HermesMetrics import pl.allegro.tech.hermes.common.metric.MetricsFacade -import pl.allegro.tech.hermes.common.metric.Timers -import pl.allegro.tech.hermes.metrics.PathsCompiler import pl.allegro.tech.hermes.schema.RawSchemaClient import pl.allegro.tech.hermes.schema.SchemaVersion import pl.allegro.tech.hermes.test.helper.metrics.MicrometerUtils @@ -29,9 +25,8 @@ class ReadMetricsTrackingRawSchemaClientTest extends Specification { RawSchema schema = RawSchema.valueOf("some_schema") MeterRegistry meterRegistry = new SimpleMeterRegistry() - HermesMetrics hermesMetrics = new HermesMetrics(new MetricRegistry(), new PathsCompiler("")) - MetricsFacade metricsFacade = new MetricsFacade(meterRegistry, hermesMetrics) + MetricsFacade metricsFacade = new MetricsFacade(meterRegistry) RawSchemaClient rawSchemaClient = Mock() @@ -91,17 +86,15 @@ class ReadMetricsTrackingRawSchemaClientTest extends Specification { } private long getSchemaCounterValue() { - return getCounterValue("schema.get-schema", Timers.GET_SCHEMA_LATENCY) + return getCounterValue("schema.get-schema") } private long getVersionsCounterValue() { - return getCounterValue("schema.get-versions", Timers.GET_SCHEMA_VERSIONS_LATENCY) + return getCounterValue("schema.get-versions") } - private long getCounterValue(String meterRegistryName, String hermesMetricsName) { + private long getCounterValue(String meterRegistryName) { def meterRegistryCount = MicrometerUtils.metricValue(meterRegistry, meterRegistryName, Search.&timer, Timer.&count).orElse(0L); - def hermesMetricsCount = hermesMetrics.schemaTimer(hermesMetricsName).count - assert meterRegistryCount == hermesMetricsCount return meterRegistryCount } } diff --git a/hermes-common/src/test/groovy/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperWorkloadConstraintsCacheTest.groovy b/hermes-common/src/test/groovy/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperWorkloadConstraintsCacheTest.groovy index 07cb8e1a60..e42121af43 100644 --- a/hermes-common/src/test/groovy/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperWorkloadConstraintsCacheTest.groovy +++ b/hermes-common/src/test/groovy/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperWorkloadConstraintsCacheTest.groovy @@ -5,6 +5,7 @@ import ch.qos.logback.classic.Logger import ch.qos.logback.classic.spi.ILoggingEvent import ch.qos.logback.core.read.ListAppender import com.fasterxml.jackson.databind.ObjectMapper +import org.awaitility.Awaitility import org.slf4j.LoggerFactory import pl.allegro.tech.hermes.api.Constraints import pl.allegro.tech.hermes.api.SubscriptionName @@ -14,8 +15,8 @@ import pl.allegro.tech.hermes.test.IntegrationTest import java.util.concurrent.TimeUnit -import static com.jayway.awaitility.Awaitility.await import static java.util.Collections.emptyMap +import static org.awaitility.Awaitility.await class ZookeeperWorkloadConstraintsCacheTest extends IntegrationTest { diff --git a/hermes-common/src/test/groovy/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperWorkloadConstraintsRepositoryTest.groovy b/hermes-common/src/test/groovy/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperWorkloadConstraintsRepositoryTest.groovy index 485def9354..98f069b7a3 100644 --- a/hermes-common/src/test/groovy/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperWorkloadConstraintsRepositoryTest.groovy +++ b/hermes-common/src/test/groovy/pl/allegro/tech/hermes/infrastructure/zookeeper/ZookeeperWorkloadConstraintsRepositoryTest.groovy @@ -2,6 +2,7 @@ package pl.allegro.tech.hermes.infrastructure.zookeeper import com.fasterxml.jackson.databind.ObjectMapper import org.apache.zookeeper.KeeperException +import org.awaitility.Awaitility import pl.allegro.tech.hermes.api.SubscriptionName import pl.allegro.tech.hermes.api.TopicName import pl.allegro.tech.hermes.api.Constraints @@ -13,7 +14,8 @@ import pl.allegro.tech.hermes.test.IntegrationTest import java.util.concurrent.TimeUnit -import static com.jayway.awaitility.Awaitility.await +import static org.awaitility.Awaitility.await + class ZookeeperWorkloadConstraintsRepositoryTest extends IntegrationTest { diff --git a/hermes-common/src/test/groovy/pl/allegro/tech/hermes/infrastructure/zookeeper/cache/HierarchicalCacheTest.groovy b/hermes-common/src/test/groovy/pl/allegro/tech/hermes/infrastructure/zookeeper/cache/HierarchicalCacheTest.groovy index 64411665ed..48b9c9490d 100644 --- a/hermes-common/src/test/groovy/pl/allegro/tech/hermes/infrastructure/zookeeper/cache/HierarchicalCacheTest.groovy +++ b/hermes-common/src/test/groovy/pl/allegro/tech/hermes/infrastructure/zookeeper/cache/HierarchicalCacheTest.groovy @@ -1,16 +1,16 @@ package pl.allegro.tech.hermes.infrastructure.zookeeper.cache -import com.jayway.awaitility.Duration -import com.jayway.awaitility.groovy.AwaitilityTrait +import org.awaitility.Awaitility import pl.allegro.tech.hermes.test.IntegrationTest +import java.time.Duration import java.util.concurrent.Executors -import static com.jayway.awaitility.Awaitility.await import static org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type.CHILD_ADDED import static org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type.CHILD_REMOVED +import static org.awaitility.Awaitility.await -class HierarchicalCacheTest extends IntegrationTest implements AwaitilityTrait { +class HierarchicalCacheTest extends IntegrationTest { private HierarchicalCache cache = new HierarchicalCache( zookeeper(), @@ -48,7 +48,7 @@ class HierarchicalCacheTest extends IntegrationTest implements AwaitilityTrait { .and().commit() then: - await().atMost(Duration.FIVE_SECONDS).until({ + await().atMost(Duration.ofSeconds(5)).until({ calledCallbacks.contains(new Tuple(CHILD_ADDED, '/hierarchicalCacheTest/groups/groupA', 'groupA')) }) @@ -59,7 +59,7 @@ class HierarchicalCacheTest extends IntegrationTest implements AwaitilityTrait { .and().commit() then: - await().atMost(Duration.FIVE_SECONDS).until({ + await().atMost(Duration.ofSeconds(5)).until({ calledCallbacks.contains(new Tuple(CHILD_ADDED, '/hierarchicalCacheTest/groups/groupA/topics/topicA', 'topicA')) }) @@ -67,7 +67,7 @@ class HierarchicalCacheTest extends IntegrationTest implements AwaitilityTrait { zookeeper().create().forPath('/hierarchicalCacheTest/groups/groupA/topics/topicA/subscriptions/subA', 'subA'.bytes) then: - await().atMost(Duration.FIVE_SECONDS).until({ + await().atMost(Duration.ofSeconds(5)).until({ calledCallbacks.contains(new Tuple(CHILD_ADDED, '/hierarchicalCacheTest/groups/groupA/topics/topicA/subscriptions/subA', 'subA')) }) @@ -89,7 +89,7 @@ class HierarchicalCacheTest extends IntegrationTest implements AwaitilityTrait { cache.start() then: - await().atMost(Duration.FIVE_SECONDS).until({ + await().atMost(Duration.ofSeconds(5)).until({ calledCallbacks.contains(new Tuple(CHILD_ADDED, '/hierarchicalCacheTest/groups/groupB', 'groupB')) && calledCallbacks.contains(new Tuple(CHILD_ADDED, '/hierarchicalCacheTest/groups/groupB/topics/topicB', 'topicB')) && calledCallbacks.contains(new Tuple(CHILD_ADDED, '/hierarchicalCacheTest/groups/groupB/topics/topicB/subscriptions/subB', 'subB')) @@ -110,7 +110,7 @@ class HierarchicalCacheTest extends IntegrationTest implements AwaitilityTrait { '/hierarchicalCacheTest/groups/groupC/topics/topicC/metrics/published', '123'.bytes) then: - await().atMost(Duration.FIVE_SECONDS).until({ + await().atMost(Duration.ofSeconds(5)).until({ calledCallbacks.contains( new Tuple(CHILD_REMOVED, '/hierarchicalCacheTest/groups/groupC/topics/topicC', '')) }) @@ -143,7 +143,7 @@ class HierarchicalCacheTest extends IntegrationTest implements AwaitilityTrait { '/hierarchicalCacheTest/workload/runtime/topic$subscription/hs-consumer1', 'AUTO_ASSIGNED'.bytes) then: - await().atMost(Duration.FIVE_SECONDS).until({ + await().atMost(Duration.ofSeconds(5)).until({ calledCallbacks.contains(new Tuple(CHILD_ADDED, '/hierarchicalCacheTest/workload/runtime/topic$subscription', '')) && !calledCallbacks.contains(new Tuple(CHILD_REMOVED, '/hierarchicalCacheTest/workload/runtime/topic$subscription', '')) }) diff --git a/hermes-common/src/test/java/pl/allegro/tech/hermes/common/message/undelivered/ZookeeperUndeliveredMessageLogTest.java b/hermes-common/src/test/java/pl/allegro/tech/hermes/common/message/undelivered/ZookeeperUndeliveredMessageLogTest.java index 0de45d0638..648f61134e 100644 --- a/hermes-common/src/test/java/pl/allegro/tech/hermes/common/message/undelivered/ZookeeperUndeliveredMessageLogTest.java +++ b/hermes-common/src/test/java/pl/allegro/tech/hermes/common/message/undelivered/ZookeeperUndeliveredMessageLogTest.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.common.message.undelivered; -import com.codahale.metrics.MetricRegistry; import com.fasterxml.jackson.databind.ObjectMapper; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.DistributionSummary; @@ -12,10 +11,8 @@ import org.junit.Test; import pl.allegro.tech.hermes.api.SentMessageTrace; import pl.allegro.tech.hermes.api.TopicName; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; import pl.allegro.tech.hermes.infrastructure.zookeeper.ZookeeperPaths; -import pl.allegro.tech.hermes.metrics.PathsCompiler; import pl.allegro.tech.hermes.test.helper.zookeeper.ZookeeperBaseTest; import java.util.Optional; @@ -34,10 +31,8 @@ public class ZookeeperUndeliveredMessageLogTest extends ZookeeperBaseTest { private final ZookeeperPaths paths = new ZookeeperPaths("/hermes"); - private final HermesMetrics hermesMetrics = new HermesMetrics( - new MetricRegistry(), new PathsCompiler("host")); private final MeterRegistry meterRegistry = new SimpleMeterRegistry(); - private final MetricsFacade metricsFacade = new MetricsFacade(meterRegistry, hermesMetrics); + private final MetricsFacade metricsFacade = new MetricsFacade(meterRegistry); private final ZookeeperUndeliveredMessageLog log = new ZookeeperUndeliveredMessageLog( zookeeperClient, @@ -60,8 +55,6 @@ public void setUp() throws Exception { @After public void cleanUp() throws Exception { deleteData(paths.basePath()); - hermesMetrics.unregister(PERSISTED_UNDELIVERED_MESSAGES_METER); - hermesMetrics.unregister(PERSISTED_UNDELIVERED_MESSAGE_SIZE); } @Test @@ -129,8 +122,6 @@ private SentMessageTrace createUndeliveredMessage(String subscription, String me } private void assertThatMetricsHaveBeenReported(int persistedMessageCount) { - assertThat(hermesMetrics.meter(PERSISTED_UNDELIVERED_MESSAGES_METER).getCount()).isEqualTo(persistedMessageCount); - assertThat(hermesMetrics.histogram(PERSISTED_UNDELIVERED_MESSAGE_SIZE).getCount()).isEqualTo(persistedMessageCount); assertThat(metricValue(meterRegistry, PERSISTED_UNDELIVERED_MESSAGES_METER, Search::counter, Counter::count).orElse(0.0d)) .isEqualTo(persistedMessageCount); assertThat(metricValue(meterRegistry, PERSISTED_UNDELIVERED_MESSAGE_SIZE + ".bytes", Search::summary, DistributionSummary::count) diff --git a/hermes-common/src/test/java/pl/allegro/tech/hermes/common/message/wrapper/MessageContentWrapperTest.java b/hermes-common/src/test/java/pl/allegro/tech/hermes/common/message/wrapper/MessageContentWrapperTest.java index 3a38d65ca8..af5b937bed 100644 --- a/hermes-common/src/test/java/pl/allegro/tech/hermes/common/message/wrapper/MessageContentWrapperTest.java +++ b/hermes-common/src/test/java/pl/allegro/tech/hermes/common/message/wrapper/MessageContentWrapperTest.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.common.message.wrapper; -import com.codahale.metrics.MetricRegistry; import com.fasterxml.jackson.databind.ObjectMapper; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; @@ -9,12 +8,9 @@ import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.apache.avro.Schema; import org.apache.commons.collections4.map.HashedMap; -import org.junit.Before; import org.junit.Test; import pl.allegro.tech.hermes.api.Topic; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; -import pl.allegro.tech.hermes.metrics.PathsCompiler; import pl.allegro.tech.hermes.schema.CompiledSchema; import pl.allegro.tech.hermes.schema.CompiledSchemaRepository; import pl.allegro.tech.hermes.schema.SchemaId; @@ -48,10 +44,8 @@ public class MessageContentWrapperTest { private static final int ID_THREE = 3; private static final int ID_FIVE = 5; - private final MetricRegistry metricRegistry = new MetricRegistry(); private final MeterRegistry meterRegistry = new SimpleMeterRegistry(); - private final HermesMetrics hermesMetrics = new HermesMetrics(metricRegistry, new PathsCompiler("")); - private final MetricsFacade metricsFacade = new MetricsFacade(meterRegistry, hermesMetrics); + private final MetricsFacade metricsFacade = new MetricsFacade(meterRegistry); private final JsonMessageContentWrapper jsonWrapper = new JsonMessageContentWrapper("message", "metadata", new ObjectMapper()); private final AvroMessageContentWrapper avroWrapper = new AvroMessageContentWrapper(Clock.systemDefaultZone()); @@ -135,11 +129,6 @@ public CompiledSchema getSchema(Topic topic, SchemaId id) { static SchemaRepository schemaRepository = new SchemaRepository(schemaVersionsRepository, compiledSchemaRepository); - @Before - public void clean() { - metricRegistry.getCounters().forEach((s, counter) -> counter.dec(counter.getCount())); - } - @Test public void shouldUnwrapMessageUsingSchemaIdFromPayload() { // given @@ -327,46 +316,33 @@ private void assertMetrics(int missedSchemaIdInPayload, int usingHeaderSchemaId, int usingSchemaVersionTruncation) { final String basePath = "content.avro.deserialization"; - assertThat(metricRegistryCounterValue(basePath + ".missed.schemaIdInPayload")).isEqualTo(missedSchemaIdInPayload); assertThat(meterRegistryCounterValue(basePath + ".missing_schemaIdInPayload", Tags.empty())) .isEqualTo(missedSchemaIdInPayload); - assertThat(metricRegistryCounterValue(basePath + ".errors.payloadWithSchemaId")).isEqualTo(errorsForPayloadWithSchemaId); assertThat(meterRegistryCounterValue(basePath + ".errors", Tags.of("deserialization_type", "payloadWithSchemaId"))) .isEqualTo(errorsForPayloadWithSchemaId); - assertThat(metricRegistryCounterValue(basePath + ".errors.headerSchemaVersion")).isEqualTo(errorsForHeaderSchemaVersion); assertThat(meterRegistryCounterValue(basePath + ".errors", Tags.of("deserialization_type", "headerSchemaVersion"))) .isEqualTo(errorsForHeaderSchemaVersion); - assertThat(metricRegistryCounterValue(basePath + ".errors.headerSchemaId")).isEqualTo(errorsForHeaderSchemaId); assertThat(meterRegistryCounterValue(basePath + ".errors", Tags.of("deserialization_type", "headerSchemaId"))) .isEqualTo(errorsForHeaderSchemaId); - assertThat(metricRegistryCounterValue(basePath + ".errors.schemaVersionTruncation")).isEqualTo(errorsWithSchemaVersionTruncation); assertThat(meterRegistryCounterValue(basePath + ".errors", Tags.of("deserialization_type", "schemaVersionTruncation"))) .isEqualTo(errorsWithSchemaVersionTruncation); - assertThat(metricRegistryCounterValue(basePath + ".using.schemaIdAware")).isEqualTo(usingSchemaIdAware); assertThat(meterRegistryCounterValue(basePath, Tags.of("deserialization_type", "payloadWithSchemaId"))) .isEqualTo(usingSchemaIdAware); - assertThat(metricRegistryCounterValue(basePath + ".using.headerSchemaVersion")).isEqualTo(usingHeaderSchemaVersion); assertThat(meterRegistryCounterValue(basePath, Tags.of("deserialization_type", "headerSchemaVersion"))) .isEqualTo(usingHeaderSchemaVersion); - assertThat(metricRegistryCounterValue(basePath + ".using.headerSchemaId")).isEqualTo(usingHeaderSchemaId); assertThat(meterRegistryCounterValue(basePath, Tags.of("deserialization_type", "headerSchemaId"))).isEqualTo(usingHeaderSchemaId); - assertThat(metricRegistryCounterValue(basePath + ".using.schemaVersionTruncation")).isEqualTo(usingSchemaVersionTruncation); assertThat(meterRegistryCounterValue(basePath, Tags.of("deserialization_type", "schemaVersionTruncation"))) .isEqualTo(usingSchemaVersionTruncation); } - private long metricRegistryCounterValue(String metricName) { - return metricRegistry.counter(metricName).getCount(); - } - private int meterRegistryCounterValue(String metricName, Tags tags) { return MicrometerUtils.metricValue(meterRegistry, metricName, tags, Search::counter, Counter::count).orElse(0.0d).intValue(); } diff --git a/hermes-common/src/test/java/pl/allegro/tech/hermes/common/message/wrapper/SchemaAwareSerDeTest.java b/hermes-common/src/test/java/pl/allegro/tech/hermes/common/message/wrapper/SchemaAwareSerDeTest.java index 3ffa2ba9e2..a11f0b8833 100644 --- a/hermes-common/src/test/java/pl/allegro/tech/hermes/common/message/wrapper/SchemaAwareSerDeTest.java +++ b/hermes-common/src/test/java/pl/allegro/tech/hermes/common/message/wrapper/SchemaAwareSerDeTest.java @@ -1,18 +1,17 @@ package pl.allegro.tech.hermes.common.message.wrapper; -import org.testng.annotations.Test; +import org.junit.Test; import pl.allegro.tech.hermes.schema.SchemaId; import pl.allegro.tech.hermes.test.helper.avro.AvroUser; -import java.io.IOException; - import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertThrows; public class SchemaAwareSerDeTest { static final AvroUser avro = new AvroUser("bob", 10, "red"); @Test - public void shouldSerialize() throws IOException { + public void shouldSerialize() { // given SchemaId id = SchemaId.valueOf(8); @@ -24,7 +23,7 @@ public void shouldSerialize() throws IOException { } @Test - public void shouldDeserialize() throws IOException { + public void shouldDeserialize() { // given byte[] serialized = SchemaAwareSerDe.serialize(SchemaId.valueOf(8), avro.asBytes()); @@ -36,11 +35,9 @@ public void shouldDeserialize() throws IOException { assertThat(deserialized.getPayload()).isEqualTo(avro.asBytes()); } - @Test(expectedExceptions = { DeserializationException.class }) - public void shouldThrowExceptionWhenDeserializingWithoutMagicByte() throws IOException { + @Test + public void shouldThrowExceptionWhenDeserializingWithoutMagicByte() { // when - SchemaAwareSerDe.deserialize(new byte[]{1, 2, 3}); - - // then exception is thrown + assertThrows(DeserializationException.class, () -> SchemaAwareSerDe.deserialize(new byte[]{1, 2, 3})); } } diff --git a/hermes-common/src/test/java/pl/allegro/tech/hermes/common/metric/counter/zookeeper/ZookeeperCounterReporterTest.java b/hermes-common/src/test/java/pl/allegro/tech/hermes/common/metric/counter/zookeeper/ZookeeperCounterReporterTest.java index 5ded453054..a974a283b0 100644 --- a/hermes-common/src/test/java/pl/allegro/tech/hermes/common/metric/counter/zookeeper/ZookeeperCounterReporterTest.java +++ b/hermes-common/src/test/java/pl/allegro/tech/hermes/common/metric/counter/zookeeper/ZookeeperCounterReporterTest.java @@ -1,23 +1,19 @@ package pl.allegro.tech.hermes.common.metric.counter.zookeeper; -import com.codahale.metrics.MetricRegistry; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import pl.allegro.tech.hermes.api.SubscriptionName; import pl.allegro.tech.hermes.api.TopicName; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; import pl.allegro.tech.hermes.common.metric.counter.CounterStorage; import pl.allegro.tech.hermes.common.util.InstanceIdResolver; -import pl.allegro.tech.hermes.metrics.PathsCompiler; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class ZookeeperCounterReporterTest { @@ -34,8 +30,7 @@ public class ZookeeperCounterReporterTest { private final MeterRegistry meterRegistry = new SimpleMeterRegistry(); - private final MetricsFacade metricsFacade = new MetricsFacade( - meterRegistry, new HermesMetrics(new MetricRegistry(), new PathsCompiler("localhost"))); + private final MetricsFacade metricsFacade = new MetricsFacade(meterRegistry); @Mock private InstanceIdResolver instanceIdResolver; @@ -44,7 +39,6 @@ public class ZookeeperCounterReporterTest { @Before public void before() { - when(instanceIdResolver.resolve()).thenReturn("localhost.domain"); zookeeperCounterReporter = new ZookeeperCounterReporter(meterRegistry, counterStorage, ""); } diff --git a/hermes-common/src/test/java/pl/allegro/tech/hermes/common/metric/counter/zookeeper/ZookeeperCounterStorageTest.java b/hermes-common/src/test/java/pl/allegro/tech/hermes/common/metric/counter/zookeeper/ZookeeperCounterStorageTest.java index 4434989d2b..2d92eec12a 100644 --- a/hermes-common/src/test/java/pl/allegro/tech/hermes/common/metric/counter/zookeeper/ZookeeperCounterStorageTest.java +++ b/hermes-common/src/test/java/pl/allegro/tech/hermes/common/metric/counter/zookeeper/ZookeeperCounterStorageTest.java @@ -4,7 +4,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; import pl.allegro.tech.hermes.api.TopicName; import pl.allegro.tech.hermes.domain.subscription.SubscriptionNotExistsException; import pl.allegro.tech.hermes.domain.subscription.SubscriptionRepository; @@ -14,7 +15,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) @@ -88,6 +88,6 @@ public void shouldNotIncrementSharedCounterForNonExistingSubscription() { storage.setSubscriptionDeliveredCounter(topicName, subscriptionName, 1L); //then - verifyZeroInteractions(sharedCounter); + Mockito.verifyNoInteractions(sharedCounter); } } \ No newline at end of file diff --git a/hermes-console/src/components/console-alert/ConsoleAlert.vue b/hermes-console/src/components/console-alert/ConsoleAlert.vue index 98ab23e19e..8b71ad7936 100644 --- a/hermes-console/src/components/console-alert/ConsoleAlert.vue +++ b/hermes-console/src/components/console-alert/ConsoleAlert.vue @@ -4,6 +4,8 @@ title?: string; text: string; type: 'error' | 'success' | 'warning' | 'info'; + link?: string; + linkDescription?: string; }>(); @@ -15,7 +17,14 @@ :type="props.type" border="start" :icon="icon ?? `\$${type}`" - > + > + {{ linkDescription }} + diff --git a/hermes-console/src/composables/subscription/use-subscription-filters-debug/useSubscriptionFiltersDebug.ts b/hermes-console/src/composables/subscription/use-subscription-filters-debug/useSubscriptionFiltersDebug.ts index 43bc147515..35f7045596 100644 --- a/hermes-console/src/composables/subscription/use-subscription-filters-debug/useSubscriptionFiltersDebug.ts +++ b/hermes-console/src/composables/subscription/use-subscription-filters-debug/useSubscriptionFiltersDebug.ts @@ -35,6 +35,15 @@ const toFiltersJSON = ( }; }; +// https://stackoverflow.com/a/30106551 +function b64EncodeUnicode(str: string): string { + return btoa( + encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) { + return String.fromCharCode(parseInt(p1, 16)); + }), + ); +} + export function useSubscriptionFiltersDebug(): UseSubscriptionFiltersDebug { const notificationStore = useNotificationsStore(); const status: Ref = ref(); @@ -52,7 +61,7 @@ export function useSubscriptionFiltersDebug(): UseSubscriptionFiltersDebug { ); const response = ( await verifyFilters(topicName, { - message: btoa(message), + message: b64EncodeUnicode(message), filters: filtersJSON, }) ).data; diff --git a/hermes-console/src/composables/topic/use-create-topic/useCreateTopic.ts b/hermes-console/src/composables/topic/use-create-topic/useCreateTopic.ts index 995bf2134d..cb2ca34f15 100644 --- a/hermes-console/src/composables/topic/use-create-topic/useCreateTopic.ts +++ b/hermes-console/src/composables/topic/use-create-topic/useCreateTopic.ts @@ -103,7 +103,7 @@ function initializeForm(form: Ref): void { trackingEnabled: false, contentType: loadedConfig.value.topic.defaults.contentType, maxMessageSize: defaultMaxMessageSize, - ack: loadedConfig.value.topic.defaults.ack, + ack: '', schema: '', }; } diff --git a/hermes-console/src/composables/topic/use-form-topic/types.ts b/hermes-console/src/composables/topic/use-form-topic/types.ts index 55d2ef1a5b..57c27946ad 100644 --- a/hermes-console/src/composables/topic/use-form-topic/types.ts +++ b/hermes-console/src/composables/topic/use-form-topic/types.ts @@ -53,6 +53,7 @@ export interface FormValidators { retentionTimeDuration: FieldValidator[]; maxMessageSize: FieldValidator[]; offlineRetentionTime: FieldValidator[]; + ack: FieldValidator[]; } export interface RawDataSources { diff --git a/hermes-console/src/composables/topic/use-form-topic/useFormTopic.ts b/hermes-console/src/composables/topic/use-form-topic/useFormTopic.ts index adb5f29dd7..f5ac01b391 100644 --- a/hermes-console/src/composables/topic/use-form-topic/useFormTopic.ts +++ b/hermes-console/src/composables/topic/use-form-topic/useFormTopic.ts @@ -41,6 +41,7 @@ function formValidators(): FormValidators { retentionTimeDuration: [required(), min(0), max(7)], maxMessageSize: [required(), min(0)], offlineRetentionTime: [required(), min(0)], + ack: [required()], }; } diff --git a/hermes-console/src/dummy/topic-form.ts b/hermes-console/src/dummy/topic-form.ts index f6f667fb36..aeca54e7c9 100644 --- a/hermes-console/src/dummy/topic-form.ts +++ b/hermes-console/src/dummy/topic-form.ts @@ -46,6 +46,7 @@ export const dummyTopicFormValidator = { retentionTimeDuration: [required(), min(0), max(7)], maxMessageSize: [required(), min(0)], offlineRetentionTime: [required(), min(0)], + ack: [required()], }; export const dummyContentTypes = [ @@ -123,7 +124,7 @@ export const dummyInitializedTopicForm = { trackingEnabled: false, contentType: dummyAppConfig.topic.defaults.contentType, maxMessageSize: defaultMaxMessageSize, - ack: dummyAppConfig.topic.defaults.ack, + ack: '', schema: '', }; diff --git a/hermes-console/src/i18n/en-US/index.ts b/hermes-console/src/i18n/en-US/index.ts index da8fd9da5f..37ce1b5b14 100644 --- a/hermes-console/src/i18n/en-US/index.ts +++ b/hermes-console/src/i18n/en-US/index.ts @@ -327,10 +327,10 @@ const en_US = { modificationDate: 'Modification date', tooltips: { acknowledgement: - 'Specifies the strength of guarantees that acknowledged message was indeed persisted. In ' + - '"Leader" mode ACK is required only from topic leader, which is fast and gives 99.99999% guarantee. It might ' + - 'be not enough when cluster is unstable. "All" mode means message needs to be saved on all replicas before ' + - 'sending ACK, which is quite slow but gives 100% guarantee that message has been persisted.', + 'Specifies the strength of guarantees that acknowledged message was indeed persisted. ' + + 'With `ACK leader` message writes are replicated asynchronously, thus the acknowledgment latency will be low. However, message write may be lost when there is a topic leadership change - e.g. due to rebalance or broker restart. ' + + 'With `ACK all` messages writes are synchronously replicated to replicas. Write acknowledgement latency will be much higher than with leader ACK,' + + ' it will also have higher variance due to tail latency. However, messages will be persisted as long as the whole replica set does not go down simultaneously.', retentionTime: 'For how many hours/days message is available for subscribers after being published.', authorizedPublishers: diff --git a/hermes-console/src/i18n/en-US/topic-form.ts b/hermes-console/src/i18n/en-US/topic-form.ts index 478898b459..a857db23fc 100644 --- a/hermes-console/src/i18n/en-US/topic-form.ts +++ b/hermes-console/src/i18n/en-US/topic-form.ts @@ -32,6 +32,12 @@ const messages = { days: 'DAYS', }, ack: 'Kafka ACK level', + ackHelpTitle: 'ACK level is very important', + ackHelpText: + 'Set ACK level according to your durability and latency requirements, see: ', + ackHelpLink: + 'https://hermes-pubsub.readthedocs.io/en/latest/user/publishing/#acknowledgment-level', + ackHelpLinkDescription: 'ACK docs.', contentType: 'Content type', maxMessageSize: { label: 'Max message size', diff --git a/hermes-console/src/views/topic/topic-form/TopicForm.vue b/hermes-console/src/views/topic/topic-form/TopicForm.vue index 5c47f9fc9d..6359edad8d 100644 --- a/hermes-console/src/views/topic/topic-form/TopicForm.vue +++ b/hermes-console/src/views/topic/topic-form/TopicForm.vue @@ -218,8 +218,19 @@ :label="$t('topicForm.fields.retentionTime.duration')" /> + + + diff --git a/hermes-consumers/build.gradle b/hermes-consumers/build.gradle index 292efde6fe..37bab685a3 100644 --- a/hermes-consumers/build.gradle +++ b/hermes-consumers/build.gradle @@ -18,41 +18,34 @@ dependencies { api group: 'org.springframework.boot', name: 'spring-boot-starter', version: versions.spring api group: 'org.eclipse.jetty', name: 'jetty-alpn-java-client', version: versions.jetty api group: 'org.eclipse.jetty.http2', name: 'jetty-http2-client-transport', version: versions.jetty - - implementation group: 'org.jctools', name: 'jctools-core', version: '1.2' - - api group: 'javax.jms', name: 'javax.jms-api', version: '2.0' - implementation group: 'joda-time', name: 'joda-time', version: '2.5' - + implementation group: 'org.jctools', name: 'jctools-core', version: '4.0.3' + api group: 'jakarta.jms', name: 'jakarta.jms-api', version: '3.1.0' + implementation group: 'joda-time', name: 'joda-time', version: '2.12.7' implementation(group: 'com.github.rholder', name: 'guava-retrying', version: '2.0.0') { exclude module: 'guava' } - - implementation group: 'org.agrona', name: 'agrona', version: '1.0.6' - + implementation group: 'org.agrona', name: 'agrona', version: '1.21.1' + // TODO: can we update it ? Which version of server our clients use ? implementation(group: 'org.hornetq', name: 'hornetq-jms-client', version: '2.4.1.Final') { exclude module: 'hornetq-native' } - - api(group: 'com.google.cloud', name: 'google-cloud-pubsub', version: '1.115.1') + api group: 'com.google.cloud', name: 'google-cloud-pubsub', version: '1.128.1' + api group: 'org.apache.httpcomponents.core5', name: 'httpcore5', version: '5.2.4' testImplementation project(':hermes-test-helper') testImplementation group: 'org.apache.curator', name: 'curator-test', version: versions.curator - testImplementation group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0' + testImplementation group: 'jakarta.servlet', name: 'jakarta.servlet-api', version: '6.0.0' testImplementation project(':hermes-common') - testImplementation(group: 'com.jayway.awaitility', name: 'awaitility', version: '1.6.1') { - exclude group: 'com.jayway.jsonpath', module: 'json-path' - } - + testImplementation(group: 'org.awaitility', name: 'awaitility-groovy', version: '4.2.1') testImplementation group: 'tech.allegro.schema.json2avro', name: 'converter', version: versions.json2avro testImplementation group: 'org.spockframework', name: 'spock-core', version: versions.spock testImplementation group: 'org.spockframework', name: 'spock-junit4', version: versions.spock testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: versions.junit_jupiter - sbeClasspath group: 'uk.co.real-logic', name: 'sbe-all', version: '1.12.8' + sbeClasspath group: 'uk.co.real-logic', name: 'sbe-all', version: '1.31.1' } def generatedPath = "${buildDir}/generated/java/" @@ -90,6 +83,6 @@ sourceSets { } } -compileJava{ +compileJava { dependsOn(generateSbeStubs) } diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/CommonConfiguration.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/CommonConfiguration.java index 218ccec73f..2ea5eab12e 100644 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/CommonConfiguration.java +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/CommonConfiguration.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.consumers.config; -import com.codahale.metrics.MetricRegistry; import com.fasterxml.jackson.databind.ObjectMapper; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.composite.CompositeMeterRegistry; @@ -18,7 +17,6 @@ import pl.allegro.tech.hermes.common.concurrent.ExecutorServiceFactory; import pl.allegro.tech.hermes.common.di.factories.CuratorClientFactory; import pl.allegro.tech.hermes.common.di.factories.HermesCuratorClientFactory; -import pl.allegro.tech.hermes.common.di.factories.MetricRegistryFactory; import pl.allegro.tech.hermes.common.di.factories.MicrometerRegistryParameters; import pl.allegro.tech.hermes.common.di.factories.ModelAwareZookeeperNotifyingCacheFactory; import pl.allegro.tech.hermes.common.di.factories.ObjectMapperFactory; @@ -35,7 +33,6 @@ import pl.allegro.tech.hermes.common.message.wrapper.AvroMessageSchemaVersionTruncationContentWrapper; import pl.allegro.tech.hermes.common.message.wrapper.CompositeMessageContentWrapper; import pl.allegro.tech.hermes.common.message.wrapper.JsonMessageContentWrapper; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; import pl.allegro.tech.hermes.common.metric.counter.CounterStorage; import pl.allegro.tech.hermes.common.metric.counter.zookeeper.ZookeeperCounterStorage; @@ -82,7 +79,6 @@ @EnableConfigurationProperties({ MetricsProperties.class, MicrometerRegistryProperties.class, - GraphiteProperties.class, PrometheusProperties.class, SchemaProperties.class, ZookeeperClustersProperties.class, @@ -232,23 +228,8 @@ public WorkloadConstraintsRepository workloadConstraintsRepository(CuratorFramew } @Bean - public HermesMetrics hermesMetrics(MetricRegistry metricRegistry, - PathsCompiler pathsCompiler) { - return new HermesMetrics(metricRegistry, pathsCompiler); - } - - @Bean - public MetricsFacade metricsFacade(MeterRegistry meterRegistry, HermesMetrics hermesMetrics) { - return new MetricsFacade(meterRegistry, hermesMetrics); - } - - @Bean - public MetricRegistry metricRegistry(MetricsProperties metricsProperties, - GraphiteProperties graphiteProperties, - InstanceIdResolver instanceIdResolver, - @Named("moduleName") String moduleName) { - return new MetricRegistryFactory(metricsProperties, graphiteProperties, instanceIdResolver, moduleName) - .provide(); + public MetricsFacade metricsFacade(MeterRegistry meterRegistry) { + return new MetricsFacade(meterRegistry); } @Bean diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/ConsumerSenderConfiguration.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/ConsumerSenderConfiguration.java index 97d76ff8e8..50be00f5e7 100644 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/ConsumerSenderConfiguration.java +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/ConsumerSenderConfiguration.java @@ -262,11 +262,11 @@ public EndpointAddressResolver interpolatingEndpointAddressResolver(UriInterpola @Bean public FutureAsyncTimeout futureAsyncTimeoutFactory(InstrumentedExecutorServiceFactory executorFactory, SenderAsyncTimeoutProperties senderAsyncTimeoutProperties) { - ScheduledExecutorService timeoutExecutorService = executorFactory.getScheduledExecutorService( - "async-timeout", - senderAsyncTimeoutProperties.getThreadPoolSize(), - senderAsyncTimeoutProperties.isThreadPoolMonitoringEnabled() - ); + ScheduledExecutorService timeoutExecutorService = executorFactory.scheduledExecutorBuilder( + "async-timeout", + senderAsyncTimeoutProperties.getThreadPoolSize() + ).withMonitoringEnabled(senderAsyncTimeoutProperties.isThreadPoolMonitoringEnabled()) + .create(); return new FutureAsyncTimeout(timeoutExecutorService); } } diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/GraphiteProperties.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/GraphiteProperties.java deleted file mode 100644 index 56682552b6..0000000000 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/GraphiteProperties.java +++ /dev/null @@ -1,41 +0,0 @@ -package pl.allegro.tech.hermes.consumers.config; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import pl.allegro.tech.hermes.common.di.factories.GraphiteParameters; - -@ConfigurationProperties(prefix = "consumer.graphite") -public class GraphiteProperties implements GraphiteParameters { - - private String prefix = "stats.tech.hermes"; - - private String host = "localhost"; - - private int port = 2003; - - @Override - public String getPrefix() { - return prefix; - } - - public void setPrefix(String prefix) { - this.prefix = prefix; - } - - @Override - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - @Override - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } -} diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/MetricsProperties.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/MetricsProperties.java index b03087193b..835ccb19bd 100644 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/MetricsProperties.java +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/config/MetricsProperties.java @@ -1,52 +1,14 @@ package pl.allegro.tech.hermes.consumers.config; import org.springframework.boot.context.properties.ConfigurationProperties; -import pl.allegro.tech.hermes.common.di.factories.MetricRegistryParameters; import java.time.Duration; @ConfigurationProperties(prefix = "consumer.metrics.metric-registry") -public class MetricsProperties implements MetricRegistryParameters { - - private boolean zookeeperReporterEnabled = true; - - private boolean graphiteReporterEnabled = false; - - private boolean consoleReporterEnabled = false; +public class MetricsProperties { private Duration counterExpireAfterAccess = Duration.ofHours(72); - private String disabledAttributes = "M15_RATE, M5_RATE, MEAN, MEAN_RATE, MIN, STDDEV"; - - private Duration reportPeriod = Duration.ofSeconds(20); - - @Override - public boolean isZookeeperReporterEnabled() { - return zookeeperReporterEnabled; - } - - public void setZookeeperReporterEnabled(boolean zookeeperReporterEnabled) { - this.zookeeperReporterEnabled = zookeeperReporterEnabled; - } - - @Override - public boolean isGraphiteReporterEnabled() { - return graphiteReporterEnabled; - } - - public void setGraphiteReporterEnabled(boolean graphiteReporterEnabled) { - this.graphiteReporterEnabled = graphiteReporterEnabled; - } - - @Override - public boolean isConsoleReporterEnabled() { - return consoleReporterEnabled; - } - - public void setConsoleReporterEnabled(boolean consoleReporterEnabled) { - this.consoleReporterEnabled = consoleReporterEnabled; - } - public Duration getCounterExpireAfterAccess() { return counterExpireAfterAccess; } @@ -54,22 +16,4 @@ public Duration getCounterExpireAfterAccess() { public void setCounterExpireAfterAccess(Duration counterExpireAfterAccess) { this.counterExpireAfterAccess = counterExpireAfterAccess; } - - @Override - public String getDisabledAttributes() { - return disabledAttributes; - } - - public void setDisabledAttributes(String disabledAttributes) { - this.disabledAttributes = disabledAttributes; - } - - @Override - public Duration getReportPeriod() { - return reportPeriod; - } - - public void setReportPeriod(Duration reportPeriod) { - this.reportPeriod = reportPeriod; - } } diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/ConsumerMessageSender.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/ConsumerMessageSender.java index 4f46845e58..151235730d 100644 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/ConsumerMessageSender.java +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/ConsumerMessageSender.java @@ -7,6 +7,11 @@ import pl.allegro.tech.hermes.api.Subscription; import pl.allegro.tech.hermes.common.metric.MetricsFacade; import pl.allegro.tech.hermes.consumers.consumer.load.SubscriptionLoadRecorder; +import pl.allegro.tech.hermes.consumers.consumer.profiling.ConsumerProfiler; +import pl.allegro.tech.hermes.consumers.consumer.profiling.ConsumerRun; +import pl.allegro.tech.hermes.consumers.consumer.profiling.DefaultConsumerProfiler; +import pl.allegro.tech.hermes.consumers.consumer.profiling.Measurement; +import pl.allegro.tech.hermes.consumers.consumer.profiling.NoOpConsumerProfiler; import pl.allegro.tech.hermes.consumers.consumer.rate.InflightsPool; import pl.allegro.tech.hermes.consumers.consumer.rate.SerialConsumerRateLimiter; import pl.allegro.tech.hermes.consumers.consumer.result.ErrorHandler; @@ -107,13 +112,14 @@ public void shutdown() { } } - public void sendAsync(Message message) { + public void sendAsync(Message message, ConsumerProfiler profiler) { inflightCount.increment(); - sendAsync(message, calculateMessageDelay(message.getPublishingTimestamp())); + sendAsync(message, calculateMessageDelay(message.getPublishingTimestamp()), profiler); } - private void sendAsync(Message message, int delayMillis) { - retrySingleThreadExecutor.schedule(() -> sendMessage(message), delayMillis, TimeUnit.MILLISECONDS); + private void sendAsync(Message message, int delayMillis, ConsumerProfiler profiler) { + profiler.measure(Measurement.SCHEDULE_MESSAGE_SENDING); + retrySingleThreadExecutor.schedule(() -> sendMessage(message, profiler), delayMillis, TimeUnit.MILLISECONDS); } private int calculateMessageDelay(long publishingMessageTimestamp) { @@ -134,13 +140,15 @@ private int calculateMessageDelay(long publishingMessageTimestamp) { * Method is calling MessageSender and is registering listeners to handle response. * Main responsibility of this method is that no message will be fully processed or rejected without release on semaphore. */ - private void sendMessage(final Message message) { + private void sendMessage(final Message message, ConsumerProfiler profiler) { loadRecorder.recordSingleOperation(); + profiler.measure(Measurement.ACQUIRE_RATE_LIMITER); acquireRateLimiterWithTimer(); HermesTimerContext timer = consumerLatencyTimer.time(); + profiler.measure(Measurement.MESSAGE_SENDER_SEND); CompletableFuture response = messageSender.send(message); - response.thenAcceptAsync(new ResponseHandlingListener(message, timer), deliveryReportingExecutor) + response.thenAcceptAsync(new ResponseHandlingListener(message, timer, profiler), deliveryReportingExecutor) .exceptionally(e -> { logger.error( "An error occurred while handling message sending response of subscription {} [partition={}, offset={}, id={}]", @@ -201,21 +209,26 @@ private boolean willExceedTtl(Message message, long delay) { return message.isTtlExceeded(remainingTtl); } - private void handleFailedSending(Message message, MessageSendingResult result) { - retrySending(message, result); + private void handleFailedSending(Message message, MessageSendingResult result, ConsumerProfiler profiler) { errorHandlers.forEach(h -> h.handleFailed(message, subscription, result)); + retrySendingOrDiscard(message, result, profiler); } - private void retrySending(Message message, MessageSendingResult result) { + private void retrySendingOrDiscard(Message message, MessageSendingResult result, ConsumerProfiler profiler) { List succeededUris = result.getSucceededUris(ConsumerMessageSender.this::messageSentSucceeded); message.incrementRetryCounter(succeededUris); long retryDelay = extractRetryDelay(message, result); if (shouldAttemptResending(message, result, retryDelay)) { retries.increment(); - retrySingleThreadExecutor.schedule(() -> resend(message, result), retryDelay, TimeUnit.MILLISECONDS); + profiler.flushMeasurements(ConsumerRun.RETRIED); + ConsumerProfiler resendProfiler = subscription.isProfilingEnabled() + ? new DefaultConsumerProfiler(subscription.getQualifiedName(), subscription.getProfilingThresholdMs()) : new NoOpConsumerProfiler(); + resendProfiler.startMeasurements(Measurement.SCHEDULE_RESEND); + resendProfiler.saveRetryDelay(retryDelay); + retrySingleThreadExecutor.schedule(() -> resend(message, result, resendProfiler), retryDelay, TimeUnit.MILLISECONDS); } else { - handleMessageDiscarding(message, result); + handleMessageDiscarding(message, result, profiler); } } @@ -229,11 +242,11 @@ private long extractRetryDelay(Message message, MessageSendingResult result) { return result.getRetryAfterMillis().map(delay -> Math.min(delay, ttl)).orElse(defaultBackoff); } - private void resend(Message message, MessageSendingResult result) { + private void resend(Message message, MessageSendingResult result, ConsumerProfiler profiler) { if (result.isLoggable()) { result.getLogInfo().forEach(logInfo -> logResultInfo(message, logInfo)); } - sendMessage(message); + sendMessage(message, profiler); } private void logResultInfo(Message message, MessageSendingResultLogInfo logInfo) { @@ -244,16 +257,18 @@ private void logResultInfo(Message message, MessageSendingResultLogInfo logInfo) logInfo.getFailure()); } - private void handleMessageDiscarding(Message message, MessageSendingResult result) { + private void handleMessageDiscarding(Message message, MessageSendingResult result, ConsumerProfiler profiler) { inflight.release(); inflightCount.decrement(); errorHandlers.forEach(h -> h.handleDiscarded(message, subscription, result)); + profiler.flushMeasurements(ConsumerRun.DISCARDED); } - private void handleMessageSendingSuccess(Message message, MessageSendingResult result) { + private void handleMessageSendingSuccess(Message message, MessageSendingResult result, ConsumerProfiler profiler) { inflight.release(); inflightCount.decrement(); successHandlers.forEach(h -> h.handleSuccess(message, subscription, result)); + profiler.flushMeasurements(ConsumerRun.DELIVERED); } private boolean messageSentSucceeded(MessageSendingResult result) { @@ -277,21 +292,24 @@ class ResponseHandlingListener implements java.util.function.Consumer> schema; + private final String topic; + private final String subscription; + private final boolean hasSubscriptionIdentityHeaders; + private final ContentType contentType; + private final Optional> schema; - private long publishingTimestamp; - private long readingTimestamp; - private byte[] data; + private final long publishingTimestamp; + private final long readingTimestamp; + private final byte[] data; private int retryCounter = 0; - private long partitionAssignmentTerm = -1; - private Map externalMetadata = Collections.emptyMap(); + private final long partitionAssignmentTerm; + private final Map externalMetadata; - private List
additionalHeaders = Collections.emptyList(); + private final List
additionalHeaders; - private Set succeededUris = Sets.newHashSet(); + private final Set succeededUris = Sets.newHashSet(); private long currentMessageBackoff = -1; - private Message() {} - public Message(String id, String topic, byte[] content, @@ -118,12 +120,12 @@ public boolean isTtlExceeded(long ttlMillis) { return currentTimestamp > readingTimestamp + ttlMillis; } - public void incrementRetryCounter(Collection succeededUris) { + public synchronized void incrementRetryCounter(Collection succeededUris) { this.retryCounter++; this.succeededUris.addAll(succeededUris.stream().map(URI::toString).collect(toList())); } - public int getRetryCounter() { + public synchronized int getRetryCounter() { return retryCounter; } @@ -138,14 +140,14 @@ public String getId() { @Override public Map getExternalMetadata() { - return Collections.unmodifiableMap(externalMetadata); + return externalMetadata; } public List
getAdditionalHeaders() { - return Collections.unmodifiableList(additionalHeaders); + return additionalHeaders; } - public long updateAndGetCurrentMessageBackoff(SubscriptionPolicy subscriptionPolicy) { + public synchronized long updateAndGetCurrentMessageBackoff(SubscriptionPolicy subscriptionPolicy) { if (currentMessageBackoff == -1) { currentMessageBackoff = subscriptionPolicy.getMessageBackoff(); } else { @@ -184,7 +186,7 @@ public PartitionOffset getPartitionOffset() { return partitionOffset; } - public boolean hasNotBeenSentTo(String uri) { + public synchronized boolean hasNotBeenSentTo(String uri) { return !succeededUris.contains(uri); } @@ -201,64 +203,80 @@ public String getSubscription() { } public static class Builder { + private String id; + private PartitionOffset partitionOffset; + + private String topic; + private String subscription; + private boolean hasSubscriptionIdentityHeaders; + private ContentType contentType; + private Optional> schema; + + private long publishingTimestamp; + private long readingTimestamp; + private byte[] data; + + private long partitionAssignmentTerm = -1; + private Map externalMetadata = Collections.emptyMap(); - private final Message message; + private List
additionalHeaders = Collections.emptyList(); public Builder() { - message = new Message(); } public Builder fromMessage(Message message) { - this.message.id = message.getId(); - this.message.data = message.getData(); - this.message.contentType = message.getContentType(); - this.message.topic = message.getTopic(); - this.message.subscription = message.getSubscription(); - this.message.hasSubscriptionIdentityHeaders = message.hasSubscriptionIdentityHeaders(); - this.message.publishingTimestamp = message.getPublishingTimestamp(); - this.message.readingTimestamp = message.getReadingTimestamp(); - this.message.partitionOffset = message.partitionOffset; - this.message.partitionAssignmentTerm = message.partitionAssignmentTerm; - this.message.externalMetadata = message.getExternalMetadata(); - this.message.additionalHeaders = message.getAdditionalHeaders(); - this.message.schema = message.getSchema(); + this.id = message.getId(); + this.data = message.getData(); + this.contentType = message.getContentType(); + this.topic = message.getTopic(); + this.subscription = message.getSubscription(); + this.hasSubscriptionIdentityHeaders = message.hasSubscriptionIdentityHeaders(); + this.publishingTimestamp = message.getPublishingTimestamp(); + this.readingTimestamp = message.getReadingTimestamp(); + this.partitionOffset = message.partitionOffset; + this.partitionAssignmentTerm = message.partitionAssignmentTerm; + this.externalMetadata = message.getExternalMetadata(); + this.additionalHeaders = message.getAdditionalHeaders(); + this.schema = message.getSchema(); return this; } - public Builder withData(byte [] data) { - this.message.data = data; + public Builder withData(byte[] data) { + this.data = data; return this; } public Builder withSchema(CompiledSchema schema) { - this.message.schema = Optional.of(schema); + this.schema = Optional.of(schema); return this; } public Builder withExternalMetadata(Map externalMetadata) { - this.message.externalMetadata = ImmutableMap.copyOf(externalMetadata); + this.externalMetadata = ImmutableMap.copyOf(externalMetadata); return this; } public Builder withAdditionalHeaders(List
additionalHeaders) { - this.message.additionalHeaders = ImmutableList.copyOf(additionalHeaders); + this.additionalHeaders = ImmutableList.copyOf(additionalHeaders); return this; } public Builder withContentType(ContentType contentType) { - this.message.contentType = contentType; + this.contentType = contentType; return this; } public Builder withNoSchema() { - this.message.schema = Optional.empty(); + this.schema = Optional.empty(); return this; } public Message build() { - return message; + return new Message( + id, topic, data, contentType, schema, publishingTimestamp, readingTimestamp, partitionOffset, partitionAssignmentTerm, externalMetadata, additionalHeaders, subscription, hasSubscriptionIdentityHeaders + ); } } } diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/SerialConsumer.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/SerialConsumer.java index eadc260ba6..3a65ed3ca4 100644 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/SerialConsumer.java +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/SerialConsumer.java @@ -11,6 +11,11 @@ import pl.allegro.tech.hermes.consumers.consumer.load.SubscriptionLoadRecorder; import pl.allegro.tech.hermes.consumers.consumer.offset.OffsetQueue; import pl.allegro.tech.hermes.consumers.consumer.offset.SubscriptionPartitionOffset; +import pl.allegro.tech.hermes.consumers.consumer.profiling.ConsumerProfiler; +import pl.allegro.tech.hermes.consumers.consumer.profiling.ConsumerRun; +import pl.allegro.tech.hermes.consumers.consumer.profiling.DefaultConsumerProfiler; +import pl.allegro.tech.hermes.consumers.consumer.profiling.Measurement; +import pl.allegro.tech.hermes.consumers.consumer.profiling.NoOpConsumerProfiler; import pl.allegro.tech.hermes.consumers.consumer.rate.AdjustableSemaphore; import pl.allegro.tech.hermes.consumers.consumer.rate.SerialConsumerRateLimiter; import pl.allegro.tech.hermes.consumers.consumer.receiver.MessageReceiver; @@ -62,7 +67,6 @@ public SerialConsumer(ReceiverFactory messageReceiverFactory, OffsetQueue offsetQueue, ConsumerAuthorizationHandler consumerAuthorizationHandler, SubscriptionLoadRecorder loadRecorder) { - this.defaultInflight = commonConsumerParameters.getSerialConsumer().getInflightSize(); this.signalProcessingInterval = commonConsumerParameters.getSerialConsumer().getSignalProcessingInterval(); this.inflightSemaphore = new AdjustableSemaphore(calculateInflightSize(subscription)); @@ -96,13 +100,19 @@ private int calculateInflightSize(Subscription subscription) { @Override public void consume(Runnable signalsInterrupt) { try { + ConsumerProfiler profiler = subscription.isProfilingEnabled() ? new DefaultConsumerProfiler(subscription.getQualifiedName(), subscription.getProfilingThresholdMs()) : new NoOpConsumerProfiler(); + profiler.startMeasurements(Measurement.SIGNALS_AND_SEMAPHORE_ACQUIRE); do { loadRecorder.recordSingleOperation(); + profiler.startPartialMeasurement(Measurement.SIGNALS_INTERRUPT_RUN); signalsInterrupt.run(); + profiler.stopPartialMeasurement(); } while (!inflightSemaphore.tryAcquire(signalProcessingInterval.toMillis(), TimeUnit.MILLISECONDS)); + profiler.measure(Measurement.MESSAGE_RECEIVER_NEXT); Optional maybeMessage = messageReceiver.next(); + profiler.measure(Measurement.MESSAGE_CONVERSION); if (maybeMessage.isPresent()) { Message message = maybeMessage.get(); @@ -114,9 +124,10 @@ public void consume(Runnable signalsInterrupt) { } Message convertedMessage = messageConverterResolver.converterFor(message, subscription).convert(message, topic); - sendMessage(convertedMessage); + sendMessage(convertedMessage, profiler); } else { inflightSemaphore.release(); + profiler.flushMeasurements(ConsumerRun.EMPTY); } } catch (InterruptedException e) { logger.info("Restoring interrupted status {}", subscription.getQualifiedName(), e); @@ -126,16 +137,18 @@ public void consume(Runnable signalsInterrupt) { } } - private void sendMessage(Message message) { + private void sendMessage(Message message, ConsumerProfiler profiler) { + profiler.measure(Measurement.OFFER_INFLIGHT_OFFSET); offsetQueue.offerInflightOffset( subscriptionPartitionOffset(subscription.getQualifiedName(), message.getPartitionOffset(), message.getPartitionAssignmentTerm()) ); + profiler.measure(Measurement.TRACKERS_LOG_INFLIGHT); trackers.get(subscription).logInflight(toMessageMetadata(message, subscription)); - sender.sendAsync(message); + sender.sendAsync(message, profiler); } @Override diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/oauth/client/OAuthHttpClient.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/oauth/client/OAuthHttpClient.java index cc0dc18849..e8a82866a7 100644 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/oauth/client/OAuthHttpClient.java +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/oauth/client/OAuthHttpClient.java @@ -1,7 +1,6 @@ package pl.allegro.tech.hermes.consumers.consumer.oauth.client; import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.http.entity.ContentType; import org.eclipse.jetty.client.ContentResponse; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.Request; @@ -15,6 +14,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import static jakarta.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED; + public class OAuthHttpClient implements OAuthClient { private final HttpClient httpClient; @@ -42,7 +43,7 @@ private Request createHttpRequest(OAuthTokenRequest request) { .method(HttpMethod.POST) .headers(headers -> { headers.add(HttpHeader.KEEP_ALIVE, "true"); - headers.add(HttpHeader.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString()); + headers.add(HttpHeader.CONTENT_TYPE, APPLICATION_FORM_URLENCODED); }); addParamIfNotNull(httpRequest, OAuthTokenRequest.Param.GRANT_TYPE, request.getGrantType()); addParamIfNotNull(httpRequest, OAuthTokenRequest.Param.SCOPE, request.getScope()); diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/ConsumerProfiler.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/ConsumerProfiler.java new file mode 100644 index 0000000000..5978ab90aa --- /dev/null +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/ConsumerProfiler.java @@ -0,0 +1,27 @@ +package pl.allegro.tech.hermes.consumers.consumer.profiling; + +public interface ConsumerProfiler { + + void startMeasurements(String measurement); + + /** + * Measures the execution time of a specific piece of code. + * The measurement starts with a call to this method, + * and is terminated by another call to the same method with a different parameter (to keep the measurement continuity), + * or by calling the flushMeasurements method. + */ + void measure(String measurement); + + /** + * Measures the same piece of code several times, for example, a method call in the middle of a loop. + * Default implementation stores individual measurements, as well as their sum. + * stopPartialMeasurements should be called before measuring again. + */ + void startPartialMeasurement(String measurement); + + void stopPartialMeasurement(); + + void saveRetryDelay(long retryDelay); + + void flushMeasurements(ConsumerRun consumerRun); +} diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/ConsumerRun.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/ConsumerRun.java new file mode 100644 index 0000000000..ea4e3dbfe1 --- /dev/null +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/ConsumerRun.java @@ -0,0 +1,5 @@ +package pl.allegro.tech.hermes.consumers.consumer.profiling; + +public enum ConsumerRun { + EMPTY, DELIVERED, DISCARDED, RETRIED +} diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/DefaultConsumerProfiler.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/DefaultConsumerProfiler.java new file mode 100644 index 0000000000..347c2cc379 --- /dev/null +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/DefaultConsumerProfiler.java @@ -0,0 +1,77 @@ +package pl.allegro.tech.hermes.consumers.consumer.profiling; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StopWatch; +import pl.allegro.tech.hermes.api.SubscriptionName; + +import java.util.concurrent.TimeUnit; + +/** + * This class is designed to be fully thread safe. + */ +public class DefaultConsumerProfiler implements ConsumerProfiler { + + private static final Logger logger = LoggerFactory.getLogger(DefaultConsumerProfiler.class); + + private final SubscriptionName subscriptionName; + private final long profilingThresholdMs; + private StopWatch stopWatch; + private StopWatch partialMeasurements; + private long retryDelayMillis = 0; + + public DefaultConsumerProfiler(SubscriptionName subscriptionName, long profilingThresholdMs) { + this.subscriptionName = subscriptionName; + this.profilingThresholdMs = profilingThresholdMs; + } + + @Override + public synchronized void startMeasurements(String measurement) { + this.stopWatch = new StopWatch(); + this.stopWatch.start(measurement); + } + + @Override + public synchronized void measure(String measurement) { + this.stopWatch.stop(); + this.stopWatch.start(measurement); + } + + @Override + public synchronized void startPartialMeasurement(String measurement) { + if (partialMeasurements == null) { + partialMeasurements = new StopWatch(); + } + partialMeasurements.start(measurement); + } + + @Override + public synchronized void stopPartialMeasurement() { + partialMeasurements.stop(); + } + + @Override + public synchronized void saveRetryDelay(long retryDelay) { + this.retryDelayMillis = retryDelay; + } + + @Override + public synchronized void flushMeasurements(ConsumerRun consumerRun) { + this.stopWatch.stop(); + if (stopWatch.getTotalTimeMillis() > profilingThresholdMs) { + logMeasurements(consumerRun); + } + } + + private void logMeasurements(ConsumerRun consumerRun) { + if (partialMeasurements != null) { + logger.info("Consumer profiler measurements for subscription {} and {} run: \n {} partialMeasurements: {} retryDelayMillis {}", + subscriptionName, consumerRun, stopWatch.prettyPrint(TimeUnit.MILLISECONDS), + partialMeasurements.prettyPrint(TimeUnit.MILLISECONDS), retryDelayMillis); + } else { + logger.info("Consumer profiler measurements for subscription {} and {} run: \n {} partialMeasurements: {}, retryDelayMillis {}", + subscriptionName, consumerRun, stopWatch.prettyPrint(TimeUnit.MILLISECONDS), + null, retryDelayMillis); + } + } +} diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/Measurement.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/Measurement.java new file mode 100644 index 0000000000..a601674687 --- /dev/null +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/Measurement.java @@ -0,0 +1,15 @@ +package pl.allegro.tech.hermes.consumers.consumer.profiling; + +public class Measurement { + public static final String SIGNALS_AND_SEMAPHORE_ACQUIRE = "signalsAndSemaphoreAcquire"; + public static final String SIGNALS_INTERRUPT_RUN = "signalsInterrupt.run"; + public static final String SCHEDULE_RESEND = "schedule.resend"; + public static final String MESSAGE_RECEIVER_NEXT = "messageReceiver.next"; + public static final String MESSAGE_CONVERSION = "messageConverter.convert"; + public static final String OFFER_INFLIGHT_OFFSET = "offsetQueue.offerInflightOffset"; + public static final String TRACKERS_LOG_INFLIGHT = "trackers.logInflight"; + public static final String SCHEDULE_MESSAGE_SENDING = "retrySingleThreadExecutor.schedule"; + public static final String ACQUIRE_RATE_LIMITER = "acquireRateLimiter"; + public static final String MESSAGE_SENDER_SEND = "messageSender.send"; + public static final String HANDLERS = "handlers"; +} diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/NoOpConsumerProfiler.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/NoOpConsumerProfiler.java new file mode 100644 index 0000000000..9b3355f4a1 --- /dev/null +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/profiling/NoOpConsumerProfiler.java @@ -0,0 +1,34 @@ +package pl.allegro.tech.hermes.consumers.consumer.profiling; + +public class NoOpConsumerProfiler implements ConsumerProfiler { + + @Override + public void startMeasurements(String measurement) { + + } + + @Override + public void measure(String measurement) { + + } + + @Override + public void startPartialMeasurement(String measurement) { + + } + + @Override + public void stopPartialMeasurement() { + + } + + @Override + public void saveRetryDelay(long retryDelay) { + + } + + @Override + public void flushMeasurements(ConsumerRun consumerRun) { + + } +} diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/rate/SendCounters.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/rate/SendCounters.java index f81f9648c6..af891d932d 100644 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/rate/SendCounters.java +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/rate/SendCounters.java @@ -1,13 +1,14 @@ package pl.allegro.tech.hermes.consumers.consumer.rate; import com.google.common.util.concurrent.AtomicDouble; -import org.apache.commons.lang.math.Fraction; +import org.apache.commons.lang3.math.Fraction; import java.time.Clock; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import static org.apache.commons.lang.math.Fraction.getFraction; +import static org.apache.commons.lang3.math.Fraction.getFraction; + public class SendCounters { diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/googlepubsub/CompressionCodecFactory.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/googlepubsub/CompressionCodecFactory.java index ba46970280..b6152b1b8d 100644 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/googlepubsub/CompressionCodecFactory.java +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/googlepubsub/CompressionCodecFactory.java @@ -84,7 +84,7 @@ static class ZstandardCodecFactory extends CompressionCodecFactory { @Override Codec createInstance() { - return new ZstandardCodec(compressionLevel, true); + return new ZstandardCodec(compressionLevel, true, ZstandardCodec.DEFAULT_USE_BUFFERPOOL); } } } diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/googlepubsub/MessageCompressor.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/googlepubsub/MessageCompressor.java index bf933b18cd..ae2ed0579e 100644 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/googlepubsub/MessageCompressor.java +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/googlepubsub/MessageCompressor.java @@ -17,15 +17,18 @@ byte[] compress(byte[] data) throws IOException { Codec codec = codecFactory.createInstance(); ByteBuffer compressed = codec.compress(ByteBuffer.wrap(data)); + byte[] compressedBytes = new byte[compressed.limit()]; + compressed.get(compressedBytes); - return compressed.array(); + return compressedBytes; } byte[] decompress(byte[] data) throws IOException { Codec codec = codecFactory.createInstance(); ByteBuffer decompressed = codec.decompress(ByteBuffer.wrap(data)); - - return decompressed.array(); + byte[] decompressedBytes = new byte[decompressed.limit()]; + decompressed.get(decompressedBytes); + return decompressedBytes; } } diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/http/ByteBufferEntity.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/http/ByteBufferEntity.java deleted file mode 100644 index 44435a681b..0000000000 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/http/ByteBufferEntity.java +++ /dev/null @@ -1,131 +0,0 @@ -package pl.allegro.tech.hermes.consumers.consumer.sender.http; - -/* - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ - -import org.apache.http.annotation.Contract; -import org.apache.http.entity.AbstractHttpEntity; -import org.apache.http.entity.ContentType; -import org.apache.http.util.Args; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.channels.Channels; -import java.nio.channels.WritableByteChannel; - -/* - * CAUTION! - * This implementation comes from PR that was merged directly into hc.core5 - * which is not backwards compatible with http-components version 4. We need - * entire http stack and not just the core so we cannot use core5 yet. This - * is the last implementation that works on version 4. If it is good enough - * for hc.core5 then it should be ok for out use case. - * - * PR: https://github.com/apache/httpcore/pull/13 - * -* */ - -/** - * An entity that delivers the contents of a {@link ByteBuffer}. - */ -@Contract(threading = org.apache.http.annotation.ThreadingBehavior.UNSAFE) -public class ByteBufferEntity extends AbstractHttpEntity implements Cloneable { - - private final ByteBuffer buffer; - - private class ByteBufferInputStream extends InputStream { - - ByteBufferInputStream() { - buffer.position(0); - } - - public int read() throws IOException { - if (!buffer.hasRemaining()) { - return -1; - } - return buffer.get() & 0xFF; - } - - public int read(byte[] bytes, int off, int len) throws IOException { - if (!buffer.hasRemaining()) { - return -1; - } - - len = Math.min(len, buffer.remaining()); - buffer.get(bytes, off, len); - return len; - } - } - - public ByteBufferEntity(final ByteBuffer buffer, final ContentType contentType) { - super(); - Args.notNull(buffer, "Source byte buffer"); - this.buffer = buffer; - if (contentType != null) { - setContentType(contentType.toString()); - } - } - - public ByteBufferEntity(final ByteBuffer buffer) { - this(buffer, null); - } - - @Override - public boolean isRepeatable() { - return true; - } - - @Override - public long getContentLength() { - return buffer.limit(); - } - - @Override - public InputStream getContent() throws IOException, UnsupportedOperationException { - return new ByteBufferInputStream(); - } - - @Override - public void writeTo(OutputStream outstream) throws IOException { - Args.notNull(outstream, "Output stream"); - WritableByteChannel channel = Channels.newChannel(outstream); - channel.write(buffer); - outstream.flush(); - } - - @Override - public boolean isStreaming() { - return false; - } - - @Override - public Object clone() throws CloneNotSupportedException { - return super.clone(); - } -} diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/http/JettyMessageBatchSender.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/http/JettyMessageBatchSender.java index 386a449feb..f9abdf262f 100644 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/http/JettyMessageBatchSender.java +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/http/JettyMessageBatchSender.java @@ -1,7 +1,6 @@ package pl.allegro.tech.hermes.consumers.consumer.sender.http; -import org.apache.http.entity.ContentType; -import org.apache.http.protocol.HTTP; +import org.apache.hc.core5.http.ContentType; import org.eclipse.jetty.client.ContentResponse; import org.eclipse.jetty.client.Request; import org.slf4j.Logger; @@ -22,6 +21,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; +import static jakarta.ws.rs.core.HttpHeaders.CONTENT_TYPE; import static pl.allegro.tech.hermes.api.AvroMediaType.AVRO_BINARY; import static pl.allegro.tech.hermes.api.ContentType.AVRO; import static pl.allegro.tech.hermes.common.http.MessageMetadataHeaders.BATCH_ID; @@ -81,7 +81,7 @@ private HttpRequestHeaders buildHeaders(MessageBatch batch, HttpRequestHeaders b ContentType contentType = getMediaType(batch.getContentType()); headers.put(BATCH_ID.getName(), batch.getId()); - headers.put(HTTP.CONTENT_TYPE, contentType.getMimeType()); + headers.put(CONTENT_TYPE, contentType.getMimeType()); headers.put(RETRY_COUNT.getName(), Integer.toString(batch.getRetryCounter())); if (batch.hasSubscriptionIdentityHeaders()) { diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/http/auth/BasicAuthProvider.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/http/auth/BasicAuthProvider.java index 761f06af35..ddde76854d 100644 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/http/auth/BasicAuthProvider.java +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/consumer/sender/http/auth/BasicAuthProvider.java @@ -1,9 +1,9 @@ package pl.allegro.tech.hermes.consumers.consumer.sender.http.auth; -import org.apache.commons.codec.binary.Base64; import pl.allegro.tech.hermes.api.EndpointAddress; import java.nio.charset.StandardCharsets; +import java.util.Base64; import java.util.Optional; public class BasicAuthProvider implements HttpAuthorizationProvider { @@ -12,7 +12,7 @@ public class BasicAuthProvider implements HttpAuthorizationProvider { public BasicAuthProvider(EndpointAddress endpoint) { String credentials = endpoint.getUsername() + ":" + endpoint.getPassword(); - String encodedCredentials = Base64.encodeBase64String(credentials.getBytes(StandardCharsets.UTF_8)); + String encodedCredentials = Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8)); this.token = "Basic " + encodedCredentials; } diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/registry/ConsumerNodesRegistry.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/registry/ConsumerNodesRegistry.java index af6346de5e..fead0874cc 100644 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/registry/ConsumerNodesRegistry.java +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/registry/ConsumerNodesRegistry.java @@ -1,6 +1,6 @@ package pl.allegro.tech.hermes.consumers.registry; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.recipes.cache.PathChildrenCache; import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; @@ -23,7 +23,7 @@ import java.util.concurrent.TimeUnit; import static java.util.stream.Collectors.toList; -import static org.apache.commons.lang.StringUtils.substringAfterLast; +import static org.apache.commons.lang3.StringUtils.substringAfterLast; import static org.apache.zookeeper.CreateMode.EPHEMERAL; public class ConsumerNodesRegistry extends PathChildrenCache implements PathChildrenCacheListener { diff --git a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/uri/UriUtils.java b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/uri/UriUtils.java index 654fd535c0..287068cd3f 100644 --- a/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/uri/UriUtils.java +++ b/hermes-consumers/src/main/java/pl/allegro/tech/hermes/consumers/uri/UriUtils.java @@ -1,7 +1,7 @@ package pl.allegro.tech.hermes.consumers.uri; import com.google.common.base.Splitter; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import java.net.URI; import java.util.List; diff --git a/hermes-consumers/src/main/resources/application-integration.yaml b/hermes-consumers/src/main/resources/application-integration.yaml index 11e0d59de2..a79777f93c 100644 --- a/hermes-consumers/src/main/resources/application-integration.yaml +++ b/hermes-consumers/src/main/resources/application-integration.yaml @@ -73,12 +73,6 @@ consumer: workload: rebalanceInterval: 1s consumerPerSubscription: 1 - metrics: - metric-registry: - graphiteReporterEnabled: true - reportPeriod: 1s - graphite: - port: 18023 schema: cache: refreshAfterWrite: 1m diff --git a/hermes-consumers/src/main/resources/application-local.yaml b/hermes-consumers/src/main/resources/application-local.yaml index 08db5b9583..8777e70205 100644 --- a/hermes-consumers/src/main/resources/application-local.yaml +++ b/hermes-consumers/src/main/resources/application-local.yaml @@ -9,11 +9,6 @@ consumer: clusters: - datacenter: "dc" brokerList: "localhost:9092" - graphite: - host: "localhost" - metrics: - metrics-registry: - graphiteReporterEnabled: true workload: consumerPerSubscription: 1 schema: diff --git a/hermes-consumers/src/test/groovy/pl/allegro/tech/hermes/consumers/consumer/sender/http/HttpClientConnectionMonitoringTest.groovy b/hermes-consumers/src/test/groovy/pl/allegro/tech/hermes/consumers/consumer/sender/http/HttpClientConnectionMonitoringTest.groovy index fed0b23ef0..8c686cc39c 100644 --- a/hermes-consumers/src/test/groovy/pl/allegro/tech/hermes/consumers/consumer/sender/http/HttpClientConnectionMonitoringTest.groovy +++ b/hermes-consumers/src/test/groovy/pl/allegro/tech/hermes/consumers/consumer/sender/http/HttpClientConnectionMonitoringTest.groovy @@ -1,18 +1,15 @@ package pl.allegro.tech.hermes.consumers.consumer.sender.http -import com.codahale.metrics.MetricRegistry import com.github.tomakehurst.wiremock.WireMockServer import io.micrometer.core.instrument.MeterRegistry import io.micrometer.core.instrument.search.Search import io.micrometer.core.instrument.simple.SimpleMeterRegistry import org.eclipse.jetty.client.HttpClient -import pl.allegro.tech.hermes.common.metric.HermesMetrics import pl.allegro.tech.hermes.common.metric.MetricsFacade import pl.allegro.tech.hermes.common.metric.executor.InstrumentedExecutorServiceFactory import pl.allegro.tech.hermes.consumers.config.ConsumerSenderConfiguration import pl.allegro.tech.hermes.consumers.config.Http1ClientProperties import pl.allegro.tech.hermes.consumers.config.SslContextProperties -import pl.allegro.tech.hermes.metrics.PathsCompiler import pl.allegro.tech.hermes.test.helper.util.Ports import spock.lang.Shared import spock.lang.Specification @@ -27,10 +24,8 @@ class HttpClientConnectionMonitoringTest extends Specification { HttpClient client HttpClient batchClient - MetricRegistry metricRegistry = new MetricRegistry() - HermesMetrics hermesMetrics = new HermesMetrics(metricRegistry, new PathsCompiler("localhost")) MeterRegistry meterRegistry = new SimpleMeterRegistry() - MetricsFacade metrics = new MetricsFacade(meterRegistry, hermesMetrics) + MetricsFacade metrics = new MetricsFacade(meterRegistry) def setupSpec() { port = Ports.nextAvailable() @@ -59,13 +54,10 @@ class HttpClientConnectionMonitoringTest extends Specification { client.POST("http://localhost:${port}/hello").send() and: - def idleDropwizard = metricRegistry.gauges['http-clients.serial.http1.idle-connections'].value - def activeDropwizard = metricRegistry.gauges['http-clients.serial.http1.active-connections'].value def idleMicrometer = Search.in(meterRegistry).name("http-clients.serial.http1.idle-connections").gauge().value() def activeMicrometer = Search.in(meterRegistry).name("http-clients.serial.http1.active-connections").gauge().value() then: - idleDropwizard + activeDropwizard > 0 idleMicrometer + activeMicrometer > 0 } @@ -77,7 +69,6 @@ class HttpClientConnectionMonitoringTest extends Specification { reporter.start() then: - metricRegistry.gauges.size() == 0 Search.in(meterRegistry).gauges().size() == 0 } } diff --git a/hermes-consumers/src/test/groovy/pl/allegro/tech/hermes/consumers/supervisor/process/ConsumerProcessSupervisorTest.groovy b/hermes-consumers/src/test/groovy/pl/allegro/tech/hermes/consumers/supervisor/process/ConsumerProcessSupervisorTest.groovy index 30df929486..a40fff24f1 100644 --- a/hermes-consumers/src/test/groovy/pl/allegro/tech/hermes/consumers/supervisor/process/ConsumerProcessSupervisorTest.groovy +++ b/hermes-consumers/src/test/groovy/pl/allegro/tech/hermes/consumers/supervisor/process/ConsumerProcessSupervisorTest.groovy @@ -1,20 +1,17 @@ package pl.allegro.tech.hermes.consumers.supervisor.process -import com.codahale.metrics.MetricRegistry -import com.jayway.awaitility.Awaitility -import com.jayway.awaitility.core.ConditionFactory import io.micrometer.core.instrument.MeterRegistry import io.micrometer.core.instrument.search.Search import io.micrometer.core.instrument.simple.SimpleMeterRegistry +import org.awaitility.Awaitility +import org.awaitility.core.ConditionFactory import pl.allegro.tech.hermes.api.DeliveryType import pl.allegro.tech.hermes.api.Subscription import pl.allegro.tech.hermes.api.SubscriptionName import pl.allegro.tech.hermes.api.Topic -import pl.allegro.tech.hermes.common.metric.HermesMetrics import pl.allegro.tech.hermes.common.metric.MetricsFacade import pl.allegro.tech.hermes.consumers.config.CommonConsumerProperties import pl.allegro.tech.hermes.consumers.supervisor.ConsumersExecutorService -import pl.allegro.tech.hermes.metrics.PathsCompiler import pl.allegro.tech.hermes.test.helper.builder.TopicBuilder import spock.lang.Specification import spock.lang.Unroll @@ -26,12 +23,7 @@ import java.time.ZoneId import java.util.function.Consumer import static java.util.concurrent.TimeUnit.MILLISECONDS -import static pl.allegro.tech.hermes.consumers.supervisor.process.Signal.SignalType.COMMIT -import static pl.allegro.tech.hermes.consumers.supervisor.process.Signal.SignalType.RETRANSMIT -import static pl.allegro.tech.hermes.consumers.supervisor.process.Signal.SignalType.START -import static pl.allegro.tech.hermes.consumers.supervisor.process.Signal.SignalType.STOP -import static pl.allegro.tech.hermes.consumers.supervisor.process.Signal.SignalType.UPDATE_SUBSCRIPTION -import static pl.allegro.tech.hermes.consumers.supervisor.process.Signal.SignalType.UPDATE_TOPIC +import static pl.allegro.tech.hermes.consumers.supervisor.process.Signal.SignalType.* import static pl.allegro.tech.hermes.test.helper.builder.SubscriptionBuilder.subscription import static pl.allegro.tech.hermes.test.helper.endpoint.TimeoutAdjuster.adjust @@ -52,7 +44,6 @@ class ConsumerProcessSupervisorTest extends Specification { ConsumerProcessSupervisor supervisor MeterRegistry meterRegistry = new SimpleMeterRegistry() - MetricRegistry metricRegistry = new MetricRegistry() MetricsFacade metrics ConsumerStub consumer @@ -70,10 +61,7 @@ class ConsumerProcessSupervisorTest extends Specification { return new ConsumerProcess(startSignal, consumer, Stub(Retransmitter), clock, unhealthyAfter, onConsumerStopped) } - metrics = new MetricsFacade( - meterRegistry, - new HermesMetrics(metricRegistry, new PathsCompiler("localhost")) - ) + metrics = new MetricsFacade(meterRegistry) supervisor = new ConsumerProcessSupervisor( new ConsumersExecutorService(new CommonConsumerProperties().getThreadPoolSize(), metrics), @@ -118,7 +106,7 @@ class ConsumerProcessSupervisorTest extends Specification { } then: - await().until { + await().untilAsserted { supervisor.run() assert !supervisor.runningSubscriptionsStatus().isEmpty() assert supervisor.runningSubscriptionsStatus().first().signalTimesheet[signals.start.type] == currentTime @@ -137,7 +125,7 @@ class ConsumerProcessSupervisorTest extends Specification { } then: - await().until { + await().untilAsserted { assert consumer.tearDownCount > 0 assert consumer.wasInterrupted } @@ -153,7 +141,7 @@ class ConsumerProcessSupervisorTest extends Specification { runAndWait(supervisor) then: - await().until { + await().untilAsserted { assert !supervisor.runningSubscriptionsStatus().isEmpty() signalsToPass.forEach { assert supervisor.runningSubscriptionsStatus().first().signalTimesheet[it.type] == currentTime @@ -176,7 +164,6 @@ class ConsumerProcessSupervisorTest extends Specification { then: signalsToDrop.forEach { String signal = it.type.name() - assert metricRegistry.counter("supervisor.signal.dropped." + signal).getCount() == 1 assert Search.in(meterRegistry) .name {it.startsWith("signals.dropped")} .tag("signal", signal) diff --git a/hermes-consumers/src/test/groovy/pl/allegro/tech/hermes/consumers/supervisor/workload/weighted/WeightedWorkBalancingListenerTest.groovy b/hermes-consumers/src/test/groovy/pl/allegro/tech/hermes/consumers/supervisor/workload/weighted/WeightedWorkBalancingListenerTest.groovy index ced5eaa583..5e1f84aec3 100644 --- a/hermes-consumers/src/test/groovy/pl/allegro/tech/hermes/consumers/supervisor/workload/weighted/WeightedWorkBalancingListenerTest.groovy +++ b/hermes-consumers/src/test/groovy/pl/allegro/tech/hermes/consumers/supervisor/workload/weighted/WeightedWorkBalancingListenerTest.groovy @@ -1,14 +1,11 @@ package pl.allegro.tech.hermes.consumers.supervisor.workload.weighted -import com.codahale.metrics.MetricFilter -import com.codahale.metrics.MetricRegistry + import io.micrometer.core.instrument.search.Search import io.micrometer.core.instrument.simple.SimpleMeterRegistry import pl.allegro.tech.hermes.api.SubscriptionName -import pl.allegro.tech.hermes.common.metric.HermesMetrics import pl.allegro.tech.hermes.common.metric.MetricsFacade import pl.allegro.tech.hermes.consumers.supervisor.workload.WorkDistributionChanges -import pl.allegro.tech.hermes.metrics.PathsCompiler import pl.allegro.tech.hermes.test.helper.time.ModifiableClock import spock.lang.Specification import spock.lang.Subject @@ -25,12 +22,10 @@ class WeightedWorkBalancingListenerTest extends Specification { def subscriptionProfileRegistry = new MockSubscriptionProfileRegistry() def weightWindowSize = Duration.ofMinutes(1) def currentLoadProvider = new CurrentLoadProvider() - def metricsRegistry = new MetricRegistry() def meterRegistry = new SimpleMeterRegistry() def metrics = new WeightedWorkloadMetricsReporter( new MetricsFacade( - meterRegistry, - new HermesMetrics(metricsRegistry, new PathsCompiler("host")) + meterRegistry ) ) @@ -180,8 +175,6 @@ class WeightedWorkBalancingListenerTest extends Specification { listener.onBeforeBalancing(["c2"]) then: - metricsRegistry.getGauges(MetricFilter.contains(".c2.")).size() == 1 - metricsRegistry.getGauges(MetricFilter.contains(".c1.")).size() == 0 Search.in(meterRegistry).tag("consumer-id", "c2").gauges().size() == 1 Search.in(meterRegistry).tag("consumer-id", "c1").gauges().size() == 0 } @@ -195,7 +188,6 @@ class WeightedWorkBalancingListenerTest extends Specification { listener.onBalancingSkipped() then: - metricsRegistry.getGauges().size() == 0 Search.in(meterRegistry).gauges().size() == 0 } diff --git a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/ConsumerMessageSenderTest.java b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/ConsumerMessageSenderTest.java index a630aafcc8..31cd6539b1 100644 --- a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/ConsumerMessageSenderTest.java +++ b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/ConsumerMessageSenderTest.java @@ -4,10 +4,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import pl.allegro.tech.hermes.api.Subscription; import pl.allegro.tech.hermes.common.metric.MetricsFacade; import pl.allegro.tech.hermes.common.metric.SubscriptionMetrics; +import pl.allegro.tech.hermes.consumers.consumer.profiling.ConsumerProfiler; +import pl.allegro.tech.hermes.consumers.consumer.profiling.NoOpConsumerProfiler; import pl.allegro.tech.hermes.consumers.consumer.rate.AdjustableSemaphore; import pl.allegro.tech.hermes.consumers.consumer.rate.SerialConsumerRateLimiter; import pl.allegro.tech.hermes.consumers.consumer.result.ErrorHandler; @@ -30,14 +32,14 @@ import java.util.concurrent.Executors; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import static pl.allegro.tech.hermes.api.SubscriptionOAuthPolicy.passwordGrantOAuthPolicy; import static pl.allegro.tech.hermes.api.SubscriptionPolicy.Builder.subscriptionPolicy; @@ -89,6 +91,8 @@ public class ConsumerMessageSenderTest { private AdjustableSemaphore inflightSemaphore; + private final ConsumerProfiler profiler = new NoOpConsumerProfiler(); + private ConsumerMessageSender sender; @Mock @@ -123,17 +127,17 @@ public void shouldHandleSuccessfulSending() { when(messageSender.send(message)).thenReturn(success()); // when - sender.sendAsync(message); + sender.sendAsync(message, profiler); verify(successHandler, timeout(1000)).handleSuccess(eq(message), eq(subscription), any(MessageSendingResult.class)); // then verifySemaphoreReleased(); verifyLatencyTimersCountedTimes(subscription, 1, 1); verifyRateLimiterAcquireTimersCountedTimes(subscription, 1, 1); - verifyZeroInteractions(errorHandler); - verifyZeroInteractions(failedMeter); + verifyNoInteractions(errorHandler); + verifyNoInteractions(failedMeter); verifyRateLimiterAcquired(); - verifyZeroInteractions(retries); + verifyNoInteractions(retries); } @Test @@ -143,7 +147,7 @@ public void shouldKeepTryingToSendMessageFailedSending() { doReturn(failure()).doReturn(failure()).doReturn(success()).when(messageSender).send(message); // when - sender.sendAsync(message); + sender.sendAsync(message, profiler); verify(successHandler, timeout(1000)).handleSuccess(eq(message), eq(subscription), any(MessageSendingResult.class)); // then @@ -162,16 +166,16 @@ public void shouldDiscardMessageWhenTTLIsExceeded() { doReturn(failure()).when(messageSender).send(message); // when - sender.sendAsync(message); + sender.sendAsync(message, profiler); // then verify(errorHandler, timeout(1000)).handleDiscarded(eq(message), eq(subscription), any(MessageSendingResult.class)); verifySemaphoreReleased(); - verifyZeroInteractions(successHandler); + verifyNoInteractions(successHandler); verifyLatencyTimersCountedTimes(subscription, 1, 1); verifyRateLimiterAcquireTimersCountedTimes(subscription, 1, 1); verifyRateLimiterAcquired(); - verifyZeroInteractions(retries); + verifyNoInteractions(retries); } @Test @@ -181,16 +185,16 @@ public void shouldNotKeepTryingToSendMessageFailedWithStatusCode4xx() { doReturn(failure(403)).doReturn(success()).when(messageSender).send(message); // when - sender.sendAsync(message); + sender.sendAsync(message, profiler); // then verify(errorHandler, timeout(1000)).handleDiscarded(eq(message), eq(subscription), any(MessageSendingResult.class)); verifySemaphoreReleased(); - verifyZeroInteractions(successHandler); + verifyNoInteractions(successHandler); verifyLatencyTimersCountedTimes(subscription, 1, 1); verifyRateLimiterAcquireTimersCountedTimes(subscription, 1, 1); verifyRateLimiterAcquired(); - verifyZeroInteractions(retries); + verifyNoInteractions(retries); } @Test @@ -202,7 +206,7 @@ public void shouldKeepTryingToSendMessageFailedWithStatusCode4xxForSubscriptionW doReturn(failure(403)).doReturn(failure(403)).doReturn(failure(403)).doReturn(success()).when(messageSender).send(message); // when - sender.sendAsync(message); + sender.sendAsync(message, profiler); verify(successHandler, timeout(1000)).handleSuccess(eq(message), eq(subscriptionWith4xxRetry), any(MessageSendingResult.class)); // then @@ -227,7 +231,7 @@ public void shouldRetryOn401UnauthorizedForOAuthSecuredSubscription() { doReturn(failure(401)).doReturn(failure(401)).doReturn(success()).when(messageSender).send(message); // when - sender.sendAsync(message); + sender.sendAsync(message, profiler); // then verifyErrorHandlerHandleFailed(message, subscription, expectedNumbersOfFailures); @@ -250,7 +254,7 @@ public void shouldBackoffRetriesWhenEndpointFails() throws InterruptedException doReturn(failure(500)).when(messageSender).send(message); //when - sender.sendAsync(message); + sender.sendAsync(message, profiler); //then Thread.sleep(executionTime); @@ -267,16 +271,16 @@ public void shouldNotRetryOnRetryAfterAboveTtl() { doReturn(backoff(retrySeconds + 1)).doReturn(success()).when(messageSender).send(message); // when - sender.sendAsync(message); + sender.sendAsync(message, profiler); // then verify(errorHandler, timeout(1000)).handleDiscarded(eq(message), eq(subscription), any(MessageSendingResult.class)); verifySemaphoreReleased(); - verifyZeroInteractions(successHandler); + verifyNoInteractions(successHandler); verifyLatencyTimersCountedTimes(subscription, 1, 1); verifyRateLimiterAcquireTimersCountedTimes(subscription, 1, 1); verifyRateLimiterAcquired(); - verifyZeroInteractions(retries); + verifyNoInteractions(retries); } @Test @@ -292,12 +296,12 @@ public void shouldDeliverToModifiedEndpoint() { // when sender.updateSubscription(subscriptionWithModfiedEndpoint); - sender.sendAsync(message); + sender.sendAsync(message, profiler); // then verify(otherMessageSender, timeout(1000)).send(message); verifyRateLimiterAcquired(); - verifyZeroInteractions(retries); + verifyNoInteractions(retries); } @Test @@ -313,12 +317,12 @@ public void shouldDeliverToNewSenderAfterModifiedTimeout() { // when sender.updateSubscription(subscriptionWithModifiedTimeout); - sender.sendAsync(message); + sender.sendAsync(message, profiler); // then verify(otherMessageSender, timeout(1000)).send(message); verifyRateLimiterAcquired(); - verifyZeroInteractions(retries); + verifyNoInteractions(retries); } @Test @@ -337,14 +341,14 @@ public void shouldDelaySendingMessageForHalfSecond() { // when long sendingStartTime = System.currentTimeMillis(); - sender.sendAsync(message); + sender.sendAsync(message, profiler); verify(successHandler, timeout(1000)).handleSuccess(eq(message), eq(subscription), any(MessageSendingResult.class)); // then long sendingTime = System.currentTimeMillis() - sendingStartTime; assertThat(sendingTime).isGreaterThanOrEqualTo(500); verifyRateLimiterAcquired(); - verifyZeroInteractions(retries); + verifyNoInteractions(retries); } @Test @@ -363,14 +367,14 @@ public void shouldCalculateSendingDelayBasingOnPublishingTimestamp() { // when long sendingStartTime = System.currentTimeMillis(); - sender.sendAsync(message); + sender.sendAsync(message, profiler); verify(successHandler, timeout(500)).handleSuccess(eq(message), eq(subscription), any(MessageSendingResult.class)); // then long sendingTime = System.currentTimeMillis() - sendingStartTime; assertThat(sendingTime).isLessThan(300); verifyRateLimiterAcquired(); - verifyZeroInteractions(retries); + verifyNoInteractions(retries); } @Test @@ -386,11 +390,11 @@ public void shouldIncreaseRetryBackoffExponentially() throws InterruptedExceptio ConsumerMessageSender sender = consumerMessageSender(subscription); // when - sender.sendAsync(message); + sender.sendAsync(message, profiler); Thread.sleep(backoff + (long) multiplier * backoff - 100); // then - verifyZeroInteractions(successHandler); + verifyNoInteractions(successHandler); verifyRateLimiterAcquired(expectedNumberOfFailures); verifyRetryCounted(expectedNumberOfFailures); } @@ -409,7 +413,7 @@ public void shouldIgnoreExponentialRetryBackoffWithRetryAfter() { ConsumerMessageSender sender = consumerMessageSender(subscription); // when - sender.sendAsync(message); + sender.sendAsync(message, profiler); //then verify(successHandler, timeout(retrySeconds * 1000 * 2 + 500)) @@ -430,11 +434,11 @@ public void shouldIgnoreExponentialRetryBackoffAfterExceededTtl() throws Interru ConsumerMessageSender sender = consumerMessageSender(subscription); // when - sender.sendAsync(message); + sender.sendAsync(message, profiler); Thread.sleep(backoff + (long) multiplier * backoff + 1000); //then - verifyZeroInteractions(successHandler); + verifyNoInteractions(successHandler); verifyRateLimiterAcquired(2); verifyRetryCounted(); } diff --git a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/converter/AvroToJsonMessageConverterTest.java b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/converter/AvroToJsonMessageConverterTest.java index 9c759cdba2..d53c82e68d 100644 --- a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/converter/AvroToJsonMessageConverterTest.java +++ b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/converter/AvroToJsonMessageConverterTest.java @@ -2,7 +2,7 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import pl.allegro.tech.hermes.api.Topic; import pl.allegro.tech.hermes.consumers.consumer.Message; import pl.allegro.tech.hermes.schema.CompiledSchema; diff --git a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/rate/calculator/OutputRateCalculatorTest.java b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/rate/calculator/OutputRateCalculatorTest.java index 92117be21b..e6e80c18d1 100644 --- a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/rate/calculator/OutputRateCalculatorTest.java +++ b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/rate/calculator/OutputRateCalculatorTest.java @@ -3,7 +3,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import pl.allegro.tech.hermes.api.SubscriptionPolicy; import pl.allegro.tech.hermes.consumers.config.RateProperties; import pl.allegro.tech.hermes.consumers.consumer.rate.maxrate.NegotiatedMaxRateProvider; diff --git a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/rate/maxrate/MaxRateRegistryTest.java b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/rate/maxrate/MaxRateRegistryTest.java index d821d0fcfc..d7a2e132a5 100644 --- a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/rate/maxrate/MaxRateRegistryTest.java +++ b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/rate/maxrate/MaxRateRegistryTest.java @@ -22,7 +22,7 @@ import java.util.Collections; import java.util.concurrent.TimeUnit; -import static com.jayway.awaitility.Awaitility.await; +import static org.awaitility.Awaitility.await; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/MessageSenderFactoryTest.java b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/MessageSenderFactoryTest.java index b439fff7a8..f96e21422a 100644 --- a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/MessageSenderFactoryTest.java +++ b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/MessageSenderFactoryTest.java @@ -2,7 +2,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.googlecode.catchexception.CatchException; import org.junit.Test; import org.mockito.Mockito; import pl.allegro.tech.hermes.api.EndpointAddress; @@ -12,8 +11,8 @@ import java.util.Set; -import static com.googlecode.catchexception.CatchException.catchException; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertThrows; import static pl.allegro.tech.hermes.test.helper.builder.SubscriptionBuilder.subscription; public class MessageSenderFactoryTest { @@ -43,12 +42,8 @@ public void shouldGetProtocolNotSupportedExceptionWhenPassingUnknownUri() { MessageSenderFactory factory = new MessageSenderFactory(ImmutableList.of()); Subscription subscription = subscription("group.topic", "subscription", "unknown://localhost:8080/test").build(); - // when - catchException(factory).create(subscription, resilientMessageSender); - // then - assertThat(CatchException.caughtException()) - .isInstanceOf(EndpointProtocolNotSupportedException.class); + assertThrows(EndpointProtocolNotSupportedException.class, () -> factory.create(subscription, resilientMessageSender)); } private ProtocolMessageSenderProvider protocolMessageSenderProviderReturning(Object createdMessageSender, String protocol) { diff --git a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/http/ByteBufferEntityTest.java b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/http/ByteBufferEntityTest.java deleted file mode 100644 index ea6fefce87..0000000000 --- a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/http/ByteBufferEntityTest.java +++ /dev/null @@ -1,104 +0,0 @@ -package pl.allegro.tech.hermes.consumers.consumer.sender.http; - -/* - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ - -/* - * CAUTION! - * This implementation comes from PR that was merged directly into hc.core5 - * which is not backwards compatible with http-components version 4. We need - * entire http stack and not just the core so we cannot use core5 yet. This - * is the last implementation that works on version 4. If it is good enough - * for hc.core5 then it should be ok for out use case. - * - * PR: https://github.com/apache/httpcore/pull/13 - * -* */ - -import org.apache.http.Consts; -import org.junit.Assert; -import org.junit.Test; - -import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; - -/** - * Unit tests for {@link ByteBufferEntity}. - * - */ -public class ByteBufferEntityTest { - - @Test - public void testBasics() throws Exception { - final ByteBuffer bytes = ByteBuffer.wrap("Message content".getBytes(Consts.ASCII)); - final ByteBufferEntity httpentity = new ByteBufferEntity(bytes); - - Assert.assertEquals(bytes.capacity(), httpentity.getContentLength()); - Assert.assertNotNull(httpentity.getContent()); - Assert.assertTrue(httpentity.isRepeatable()); - Assert.assertFalse(httpentity.isStreaming()); - } - - - @Test(expected = IllegalArgumentException.class) - public void testIllegalConstructorNullByteArray() throws Exception { - new ByteBufferEntity(null); - } - - @Test - public void testWriteTo() throws Exception { - final ByteBuffer bytes = ByteBuffer.wrap("Message content".getBytes(Consts.ASCII)); - final ByteBufferEntity httpentity = new ByteBufferEntity(bytes); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - httpentity.writeTo(out); - byte[] bytes2 = out.toByteArray(); - Assert.assertNotNull(bytes2); - Assert.assertEquals(bytes.capacity(), bytes2.length); - bytes.position(0); - for (int i = 0; i < bytes2.length; i++) { - Assert.assertEquals(bytes.get(i), bytes2[i]); - } - - out = new ByteArrayOutputStream(); - httpentity.writeTo(out); - bytes2 = out.toByteArray(); - Assert.assertNotNull(bytes2); - Assert.assertEquals(bytes.capacity(), bytes2.length); - bytes.position(0); - for (int i = 0; i < bytes.capacity(); i++) { - Assert.assertEquals(bytes.get(i), bytes2[i]); - } - - try { - httpentity.writeTo(null); - Assert.fail("IllegalArgumentException should have been thrown"); - } catch (final IllegalArgumentException ex) { - // expected - } - } -} \ No newline at end of file diff --git a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/jms/JmsMessageSenderTest.java b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/jms/JmsMessageSenderTest.java index 3c4f6032e5..7255e9a62e 100644 --- a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/jms/JmsMessageSenderTest.java +++ b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/jms/JmsMessageSenderTest.java @@ -8,7 +8,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import pl.allegro.tech.hermes.consumers.consumer.Message; import pl.allegro.tech.hermes.consumers.consumer.sender.MessageSendingResult; diff --git a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/resolver/InterpolatingEndpointAddressResolverTest.java b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/resolver/InterpolatingEndpointAddressResolverTest.java index b69b4b2410..5f4c432aa8 100644 --- a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/resolver/InterpolatingEndpointAddressResolverTest.java +++ b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/consumer/sender/resolver/InterpolatingEndpointAddressResolverTest.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.consumers.consumer.sender.resolver; -import com.googlecode.catchexception.CatchException; import org.junit.Test; import pl.allegro.tech.hermes.api.EndpointAddress; import pl.allegro.tech.hermes.api.EndpointAddressResolverMetadata; @@ -11,8 +10,8 @@ import java.net.URI; import java.nio.charset.StandardCharsets; -import static com.googlecode.catchexception.CatchException.catchException; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertThrows; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static pl.allegro.tech.hermes.consumers.test.MessageBuilder.withTestMessage; @@ -41,19 +40,18 @@ public void shouldUseInterpolatorToInterpolateURI() throws InterpolationExceptio } @Test - @SuppressWarnings("unchecked") - public void shouldThrowResolvingExceptionWhenInterpolationFails() throws EndpointAddressResolutionException, InterpolationException { + public void shouldThrowResolvingExceptionWhenInterpolationFails() throws InterpolationException { // given EndpointAddress address = EndpointAddress.of("http://localhost/{a}"); Message message = withTestMessage().withContent("content", StandardCharsets.UTF_8).build(); when(interpolator.interpolate(address, message)).thenThrow(InterpolationException.class); - // when - catchException(resolver).resolve(EndpointAddress.of("http://localhost/{a}"), - withTestMessage().withContent("content", StandardCharsets.UTF_8).build(), metadata); - // then - assertThat(CatchException.caughtException()) - .isInstanceOf(EndpointAddressResolutionException.class); + assertThrows(EndpointAddressResolutionException.class, + () -> resolver.resolve( + EndpointAddress.of("http://localhost/{a}"), + withTestMessage().withContent("content", StandardCharsets.UTF_8).build(), + metadata) + ); } } diff --git a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/supervisor/workload/ConsumerTestRuntimeEnvironment.java b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/supervisor/workload/ConsumerTestRuntimeEnvironment.java index 05057dbc78..4018066ac8 100644 --- a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/supervisor/workload/ConsumerTestRuntimeEnvironment.java +++ b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/supervisor/workload/ConsumerTestRuntimeEnvironment.java @@ -56,9 +56,9 @@ import java.util.function.Supplier; import java.util.stream.IntStream; -import static com.jayway.awaitility.Awaitility.await; -import static com.jayway.awaitility.Duration.ONE_SECOND; import static java.util.stream.Collectors.toList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import static org.mockito.Mockito.mock; import static pl.allegro.tech.hermes.test.helper.builder.SubscriptionBuilder.subscription; import static pl.allegro.tech.hermes.test.helper.builder.TopicBuilder.topic; @@ -154,13 +154,13 @@ private WorkloadSupervisor createConsumer(String consumerId, new ZookeeperSubscriptionIdProvider(curator, zookeeperPaths), new CommonConsumerProperties()); ConsumerAssignmentCache consumerAssignmentCache = - new ConsumerAssignmentCache( - curator, - workloadProperties.getNodeId(), - kafkaProperties.getClusterName(), - zookeeperPaths, - subscriptionIds - ); + new ConsumerAssignmentCache( + curator, + workloadProperties.getNodeId(), + kafkaProperties.getClusterName(), + zookeeperPaths, + subscriptionIds + ); try { consumerAssignmentCache.start(); } catch (Exception e) { @@ -168,22 +168,22 @@ private WorkloadSupervisor createConsumer(String consumerId, } ClusterAssignmentCache clusterAssignmentCache = - new ClusterAssignmentCache( - curator, - kafkaProperties.getClusterName(), - zookeeperPaths, - subscriptionIds, - nodesRegistry - ); + new ClusterAssignmentCache( + curator, + kafkaProperties.getClusterName(), + zookeeperPaths, + subscriptionIds, + nodesRegistry + ); ConsumerAssignmentRegistry consumerAssignmentRegistry = - new ConsumerAssignmentRegistry( - curator, - workloadProperties.getRegistryBinaryEncoderAssignmentsBufferSizeBytes(), - kafkaProperties.getClusterName(), - zookeeperPaths, - subscriptionIds - ); + new ConsumerAssignmentRegistry( + curator, + workloadProperties.getRegistryBinaryEncoderAssignmentsBufferSizeBytes(), + kafkaProperties.getClusterName(), + zookeeperPaths, + subscriptionIds + ); return new WorkloadSupervisor( consumersSupervisor, @@ -270,8 +270,9 @@ void kill(WorkloadSupervisor node) { consumerZookeeperConnections.get(node.consumerId()).close(); } - void killAll() { + void cleanState() { consumerZookeeperConnections.values().forEach(CuratorFramework::close); + subscriptionsCaches.clear(); } private WorkloadSupervisor startNode(WorkloadSupervisor workloadSupervisor) { @@ -285,7 +286,7 @@ private WorkloadSupervisor startNode(WorkloadSupervisor workloadSupervisor) { } void waitForRegistration(String consumerId) { - await().atMost(adjust(ONE_SECOND)).until(() -> isRegistered(consumerId)); + await().atMost(adjust(Duration.ofSeconds(1))).until(() -> isRegistered(consumerId)); } private boolean isRegistered(String nodeId) { @@ -297,9 +298,7 @@ private boolean isRegistered(String nodeId) { } void awaitUntilAssignmentExists(SubscriptionName subscription, WorkloadSupervisor node) { - await().atMost(adjust(ONE_SECOND)).until(() -> { - node.assignedSubscriptions().contains(subscription); - }); + await().atMost(adjust(Duration.ofSeconds(2))).until(() -> node.assignedSubscriptions().contains(subscription)); } List createSubscription(int howMany) { @@ -321,11 +320,11 @@ private SubscriptionName createSubscription(SubscriptionName subscriptionName) { topicRepository.createTopic(topic(subscription.getTopicName()).build()); } subscriptionRepository.createSubscription(subscription); - await().atMost(adjust(ONE_SECOND)).until( + await().atMost(adjust(Duration.ofSeconds(2))).untilAsserted( () -> { - subscriptionRepository.subscriptionExists(subscription.getTopicName(), subscription.getName()); + assertThat(subscriptionRepository.subscriptionExists(subscription.getTopicName(), subscription.getName())).isTrue(); subscriptionsCaches.forEach(subscriptionsCache -> - subscriptionsCache.listActiveSubscriptionNames().contains(subscriptionName)); + assertThat(subscriptionsCache.listActiveSubscriptionNames().contains(subscriptionName)).isTrue()); } ); return subscription.getQualifiedName(); diff --git a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/supervisor/workload/WorkloadSupervisorIntegrationTest.java b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/supervisor/workload/WorkloadSupervisorIntegrationTest.java index 4c510823ef..8e609aad90 100644 --- a/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/supervisor/workload/WorkloadSupervisorIntegrationTest.java +++ b/hermes-consumers/src/test/java/pl/allegro/tech/hermes/consumers/supervisor/workload/WorkloadSupervisorIntegrationTest.java @@ -14,10 +14,9 @@ import java.time.Duration; import java.util.List; -import static com.jayway.awaitility.Awaitility.await; -import static com.jayway.awaitility.Duration.FIVE_SECONDS; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; +import static org.awaitility.Awaitility.await; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -30,7 +29,7 @@ public class WorkloadSupervisorIntegrationTest extends ZookeeperBaseTest { @Before public void setup() throws Exception { - runtime.killAll(); + runtime.cleanState(); deleteData("/hermes"); createPath("/hermes/groups"); } @@ -67,8 +66,8 @@ public void shouldElectNewLeaderAfterShutdown() { runtime.kill(leader); // then - await().atMost(adjust(FIVE_SECONDS)).until(() -> runtime.findLeader(supervisors) != leader); - await().atMost(adjust(FIVE_SECONDS)).until(() -> !leader.isLeader()); + await().atMost(adjust(Duration.ofSeconds(5))).until(() -> runtime.findLeader(supervisors) != leader); + await().atMost(adjust(Duration.ofSeconds(5))).until(() -> !leader.isLeader()); } @Test @@ -137,7 +136,7 @@ public void shouldRecreateMissingConsumer() throws Exception { monitor.start(); // then - await().atMost(FIVE_SECONDS).until( + await().atMost(Duration.ofSeconds(5)).untilAsserted( () -> verify(consumerFactory, times(2)).createConsumer(any())); shutdown(supervisor); diff --git a/hermes-frontend/build.gradle b/hermes-frontend/build.gradle index 5423631ef9..dcb9018c40 100644 --- a/hermes-frontend/build.gradle +++ b/hermes-frontend/build.gradle @@ -13,24 +13,19 @@ dependencies { api group: 'org.springframework.boot', name: 'spring-boot-starter', version: versions.spring api group: 'io.undertow', name: 'undertow-core', version: versions.undertow - implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.0' - api (group: 'net.openhft', name: 'chronicle-map', version: '3.22.9') { + // Did not update that as we're trying to abandon buffers + api(group: 'net.openhft', name: 'chronicle-map', version: '3.22.9') { exclude group: 'net.openhft', module: 'chronicle-analytics' } - implementation group: 'commons-io', name: 'commons-io', version: '2.4' + implementation group: 'commons-io', name: 'commons-io', version: '2.16.1' implementation group: 'net.jodah', name: 'failsafe', version: versions.failsafe + testImplementation project(':hermes-test-helper') + testImplementation group: 'org.spockframework', name: 'spock-core', version: versions.spock testImplementation group: 'org.apache.groovy', name: 'groovy-json', version: versions.groovy - - testImplementation(group: 'com.jayway.awaitility', name: 'awaitility-groovy', version: '1.7.0') { - exclude group: 'org.codehaus.groovy', module: 'groovy-all' - } - - testImplementation project(':hermes-test-helper') - testImplementation(group: 'com.jayway.awaitility', name: 'awaitility', version: '1.6.1') { - exclude group: 'com.jayway.jsonpath', module: 'json-path' - } + testImplementation group: 'org.awaitility', name: 'awaitility-groovy', version: '4.2.1' + testImplementation group: 'org.awaitility', name: 'awaitility', version: '4.2.1' testImplementation group: 'org.testcontainers', name: 'spock', version: versions.testcontainers testImplementation group: 'org.testcontainers', name: 'kafka', version: versions.testcontainers testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: versions.junit_jupiter diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/cache/topic/NotificationBasedTopicsCache.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/cache/topic/NotificationBasedTopicsCache.java index bf2e7a9d92..5ac0b5d232 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/cache/topic/NotificationBasedTopicsCache.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/cache/topic/NotificationBasedTopicsCache.java @@ -14,6 +14,7 @@ import pl.allegro.tech.hermes.frontend.blacklist.BlacklistZookeeperNotifyingCache; import pl.allegro.tech.hermes.frontend.blacklist.TopicBlacklistCallback; import pl.allegro.tech.hermes.frontend.metric.CachedTopic; +import pl.allegro.tech.hermes.frontend.metric.ThroughputRegistry; import java.util.List; import java.util.Optional; @@ -30,17 +31,20 @@ public class NotificationBasedTopicsCache implements TopicCallback, TopicsCache, private final TopicRepository topicRepository; private final MetricsFacade metricsFacade; private final KafkaNamesMapper kafkaNamesMapper; + private final ThroughputRegistry throughputRegistry; public NotificationBasedTopicsCache(InternalNotificationsBus notificationsBus, BlacklistZookeeperNotifyingCache blacklistZookeeperNotifyingCache, GroupRepository groupRepository, TopicRepository topicRepository, MetricsFacade metricsFacade, + ThroughputRegistry throughputRegistry, KafkaNamesMapper kafkaNamesMapper) { this.groupRepository = groupRepository; this.topicRepository = topicRepository; this.metricsFacade = metricsFacade; this.kafkaNamesMapper = kafkaNamesMapper; + this.throughputRegistry = throughputRegistry; notificationsBus.registerTopicCallback(this); blacklistZookeeperNotifyingCache.addCallback(this); } @@ -108,10 +112,10 @@ public void start() { } private CachedTopic cachedTopic(Topic topic) { - return new CachedTopic(topic, metricsFacade, kafkaNamesMapper.toKafkaTopics(topic)); + return new CachedTopic(topic, metricsFacade, throughputRegistry, kafkaNamesMapper.toKafkaTopics(topic)); } private CachedTopic bannedTopic(Topic topic) { - return new CachedTopic(topic, metricsFacade, kafkaNamesMapper.toKafkaTopics(topic), true); + return new CachedTopic(topic, metricsFacade, throughputRegistry, kafkaNamesMapper.toKafkaTopics(topic), true); } } diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/CommonConfiguration.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/CommonConfiguration.java index 92b0b446bd..d5e95e5c9f 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/CommonConfiguration.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/CommonConfiguration.java @@ -1,12 +1,10 @@ package pl.allegro.tech.hermes.frontend.config; -import com.codahale.metrics.MetricRegistry; import com.fasterxml.jackson.databind.ObjectMapper; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.composite.CompositeMeterRegistry; import io.micrometer.prometheus.PrometheusConfig; import io.micrometer.prometheus.PrometheusMeterRegistry; -import jakarta.inject.Named; import org.apache.curator.framework.CuratorFramework; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -16,7 +14,6 @@ import pl.allegro.tech.hermes.common.clock.ClockFactory; import pl.allegro.tech.hermes.common.di.factories.CuratorClientFactory; import pl.allegro.tech.hermes.common.di.factories.HermesCuratorClientFactory; -import pl.allegro.tech.hermes.common.di.factories.MetricRegistryFactory; import pl.allegro.tech.hermes.common.di.factories.MicrometerRegistryParameters; import pl.allegro.tech.hermes.common.di.factories.ModelAwareZookeeperNotifyingCacheFactory; import pl.allegro.tech.hermes.common.di.factories.ObjectMapperFactory; @@ -33,7 +30,6 @@ import pl.allegro.tech.hermes.common.message.wrapper.AvroMessageSchemaVersionTruncationContentWrapper; import pl.allegro.tech.hermes.common.message.wrapper.CompositeMessageContentWrapper; import pl.allegro.tech.hermes.common.message.wrapper.JsonMessageContentWrapper; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; import pl.allegro.tech.hermes.common.metric.counter.CounterStorage; import pl.allegro.tech.hermes.common.metric.counter.zookeeper.ZookeeperCounterStorage; @@ -82,7 +78,6 @@ @EnableConfigurationProperties({ MetricRegistryProperties.class, MicrometerRegistryProperties.class, - GraphiteProperties.class, PrometheusProperties.class, SchemaProperties.class, ZookeeperClustersProperties.class, @@ -283,23 +278,8 @@ public WorkloadConstraintsRepository workloadConstraintsRepository(CuratorFramew } @Bean - public HermesMetrics hermesMetrics(MetricRegistry metricRegistry, - PathsCompiler pathsCompiler) { - return new HermesMetrics(metricRegistry, pathsCompiler); - } - - @Bean - public MetricsFacade micrometerHermesMetrics(MeterRegistry meterRegistry, HermesMetrics hermesMetrics) { - return new MetricsFacade(meterRegistry, hermesMetrics); - } - - @Bean - public MetricRegistry metricRegistry(MetricRegistryProperties metricRegistryProperties, - GraphiteProperties graphiteProperties, - InstanceIdResolver instanceIdResolver, - @Named("moduleName") String moduleName) { - return new MetricRegistryFactory(metricRegistryProperties, graphiteProperties, - instanceIdResolver, moduleName).provide(); + public MetricsFacade micrometerHermesMetrics(MeterRegistry meterRegistry) { + return new MetricsFacade(meterRegistry); } @Bean diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FailFastKafkaProducerProperties.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FailFastKafkaProducerProperties.java index e65eb59c12..01056b10d4 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FailFastKafkaProducerProperties.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FailFastKafkaProducerProperties.java @@ -16,8 +16,6 @@ public class FailFastKafkaProducerProperties { private FallbackSchedulerProperties fallbackScheduler = new FallbackSchedulerProperties(); - private ChaosSchedulerProperties chaosScheduler = new ChaosSchedulerProperties(); - public Duration getSpeculativeSendDelay() { return speculativeSendDelay; } @@ -50,14 +48,6 @@ public void setRemote(KafkaProducerParameters remote) { this.remote = remote; } - public ChaosSchedulerProperties getChaosScheduler() { - return chaosScheduler; - } - - public void setChaosScheduler(ChaosSchedulerProperties chaosScheduler) { - this.chaosScheduler = chaosScheduler; - } - public static class FallbackSchedulerProperties { private int threadPoolSize = 16; @@ -80,27 +70,4 @@ public void setThreadPoolMonitoringEnabled(boolean threadPoolMonitoringEnabled) this.threadPoolMonitoringEnabled = threadPoolMonitoringEnabled; } } - - public static class ChaosSchedulerProperties { - - private int threadPoolSize = 16; - - private boolean threadPoolMonitoringEnabled = false; - - public int getThreadPoolSize() { - return threadPoolSize; - } - - public void setThreadPoolSize(int threadPoolSize) { - this.threadPoolSize = threadPoolSize; - } - - public boolean isThreadPoolMonitoringEnabled() { - return threadPoolMonitoringEnabled; - } - - public void setThreadPoolMonitoringEnabled(boolean threadPoolMonitoringEnabled) { - this.threadPoolMonitoringEnabled = threadPoolMonitoringEnabled; - } - } } diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FailFastLocalKafkaProducerProperties.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FailFastLocalKafkaProducerProperties.java index 7d5b24ed02..f5c53b047c 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FailFastLocalKafkaProducerProperties.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FailFastLocalKafkaProducerProperties.java @@ -4,6 +4,44 @@ import java.time.Duration; + +/** + Kafka producer maintains a single connection to each broker, over which produce request are sent. + When producer request duration exceeds requestTimeout, producer closes the connection to the broker + that the request was sent to. This causes all inflight requests that were sent to that broker to be cancelled. + The number of inflight requests is configured by maxInflightRequestsPerConnection property. + + Let's assume that we have requestTimeout set to 500ms, maxInflightRequestsPerConnection set to 5, + and there are following inflight batches in the producer being sent to broker1: + + batchId | time spent in send buffer (socket) + ------------------------------------ + batch1 | 10ms + batch2 | 200ms + batch3 | 300ms + batch4 | 400ms + batch5 | 501ms + + Batch5 exceeded the requestTimeout so producer will close the connection to broker1. This causes batch5 to be marked + as failed but also causes batches 1-4 to be retried. This has the following consequences: + 1. Batches 1-4 will probably get duplicated - even tough they were cancelled, they were probably sent to the broker, + just haven't been ACKd yet. Retry would cause them to be sent once again resulting in duplicates. + 2. On retry, batches 1-4 will have a smaller time budget to complete. Part of their budget was already wasted + in send buffer + retryBackoff will be applied to them. They will have little time to complete on retry which can cause + them to be timed out, potentially resulting in a vicious circle. + 3. Connection to the broker must be reestablished which takes time. + + To avoid problems described above we actually set requestTimeout and deliveryTimeout to be much higher than the + maximum frontend request duration (frontend.handlers.maxPublishRequestDuration). This means that when + maxPublishRequestDuration is exceeded for a message we received, a client will receive 5xx even tough the + corresponding message is still being processed in the producer. The message will eventually be ACKd by Kafka so upon client-side + retry the message will be duplicated. This however, would likely also happen if the message was promptly timed-out by producer + before maxPublishRequestDuration elapsed - the message was likely already sent to Kafka, there just haven't been a response yet. + + So by using large requestTimeout we cause the first slow message to be duplicated (by client-side retry) but: + - we protect other inflight messages from being duplicated, + - we prevent connections from being frequently dropped and reestablished. + */ public class FailFastLocalKafkaProducerProperties implements KafkaProducerParameters { private Duration maxBlock = Duration.ofMillis(500); @@ -15,9 +53,9 @@ public class FailFastLocalKafkaProducerProperties implements KafkaProducerParame private Duration retryBackoff = Duration.ofMillis(50); - private Duration requestTimeout = Duration.ofMillis(500); + private Duration requestTimeout = Duration.ofSeconds(30); - private Duration deliveryTimeout = Duration.ofMillis(500); + private Duration deliveryTimeout = Duration.ofSeconds(30); private int batchSize = 16 * 1024; diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FailFastRemoteKafkaProducerProperties.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FailFastRemoteKafkaProducerProperties.java index 1265f343bb..b051486460 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FailFastRemoteKafkaProducerProperties.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FailFastRemoteKafkaProducerProperties.java @@ -4,6 +4,10 @@ import java.time.Duration; +/** + * See {@link pl.allegro.tech.hermes.frontend.config.FailFastLocalKafkaProducerProperties} + * for the explanation of default values used. + */ public class FailFastRemoteKafkaProducerProperties implements KafkaProducerParameters { private Duration maxBlock = Duration.ofMillis(250); @@ -15,9 +19,9 @@ public class FailFastRemoteKafkaProducerProperties implements KafkaProducerParam private Duration retryBackoff = Duration.ofMillis(50); - private Duration requestTimeout = Duration.ofMillis(250); + private Duration requestTimeout = Duration.ofSeconds(30); - private Duration deliveryTimeout = Duration.ofMillis(250); + private Duration deliveryTimeout = Duration.ofSeconds(30); private int batchSize = 16 * 1024; diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FrontendConfiguration.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FrontendConfiguration.java index c219608443..a11e42a9a0 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FrontendConfiguration.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FrontendConfiguration.java @@ -16,6 +16,7 @@ import pl.allegro.tech.hermes.frontend.cache.topic.NotificationBasedTopicsCache; import pl.allegro.tech.hermes.frontend.cache.topic.TopicsCache; import pl.allegro.tech.hermes.frontend.listeners.BrokerListeners; +import pl.allegro.tech.hermes.frontend.metric.ThroughputRegistry; import pl.allegro.tech.hermes.frontend.producer.BrokerMessageProducer; import pl.allegro.tech.hermes.frontend.validator.MessageValidators; import pl.allegro.tech.hermes.frontend.validator.TopicMessageValidator; @@ -41,11 +42,12 @@ public TopicsCache notificationBasedTopicsCache(InternalNotificationsBus interna GroupRepository groupRepository, TopicRepository topicRepository, MetricsFacade metricsFacade, + ThroughputRegistry throughputRegistry, KafkaNamesMapper kafkaNamesMapper, BlacklistZookeeperNotifyingCache blacklistZookeeperNotifyingCache) { return new NotificationBasedTopicsCache(internalNotificationsBus, blacklistZookeeperNotifyingCache, - groupRepository, topicRepository, metricsFacade, kafkaNamesMapper); + groupRepository, topicRepository, metricsFacade, throughputRegistry, kafkaNamesMapper); } @Bean diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FrontendProducerConfiguration.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FrontendProducerConfiguration.java index f1265cd44e..fe70b502c2 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FrontendProducerConfiguration.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FrontendProducerConfiguration.java @@ -9,11 +9,11 @@ import pl.allegro.tech.hermes.common.metric.MetricsFacade; import pl.allegro.tech.hermes.common.metric.executor.InstrumentedExecutorServiceFactory; import pl.allegro.tech.hermes.frontend.cache.topic.TopicsCache; -import pl.allegro.tech.hermes.frontend.config.FailFastKafkaProducerProperties.ChaosSchedulerProperties; import pl.allegro.tech.hermes.frontend.config.FailFastKafkaProducerProperties.FallbackSchedulerProperties; import pl.allegro.tech.hermes.frontend.producer.BrokerLatencyReporter; import pl.allegro.tech.hermes.frontend.producer.BrokerMessageProducer; import pl.allegro.tech.hermes.frontend.producer.kafka.FallbackToRemoteDatacenterAwareMessageProducer; +import pl.allegro.tech.hermes.frontend.producer.kafka.KafkaChaosProperties; import pl.allegro.tech.hermes.frontend.producer.kafka.KafkaHeaderFactory; import pl.allegro.tech.hermes.frontend.producer.kafka.KafkaMessageSenders; import pl.allegro.tech.hermes.frontend.producer.kafka.KafkaMessageSendersFactory; @@ -42,6 +42,7 @@ KafkaHeaderNameProperties.class, KafkaProducerProperties.class, FailFastKafkaProducerProperties.class, + KafkaChaosProperties.class, KafkaClustersProperties.class, HTTPHeadersProperties.class }) @@ -69,24 +70,19 @@ public BrokerMessageProducer multiDatacenterBrokerProducer(@Named("failFastKafka AdminReadinessService adminReadinessService, InstrumentedExecutorServiceFactory executorServiceFactory) { FallbackSchedulerProperties fallbackSchedulerProperties = kafkaProducerProperties.getFallbackScheduler(); - ScheduledExecutorService fallbackScheduler = executorServiceFactory.getScheduledExecutorService( + ScheduledExecutorService fallbackScheduler = executorServiceFactory.scheduledExecutorBuilder( "fallback-to-remote", - fallbackSchedulerProperties.getThreadPoolSize(), - fallbackSchedulerProperties.isThreadPoolMonitoringEnabled() - ); - ChaosSchedulerProperties chaosSchedulerProperties = kafkaProducerProperties.getChaosScheduler(); - ScheduledExecutorService chaosScheduler = executorServiceFactory.getScheduledExecutorService( - "chaos", - chaosSchedulerProperties.getThreadPoolSize(), - chaosSchedulerProperties.isThreadPoolMonitoringEnabled() - ); + fallbackSchedulerProperties.getThreadPoolSize() + ) + .withMonitoringEnabled(fallbackSchedulerProperties.isThreadPoolMonitoringEnabled()) + .withRemoveOnCancel(true) + .create(); return new MultiDatacenterMessageProducer( kafkaMessageSenders, adminReadinessService, messageConverter, kafkaProducerProperties.getSpeculativeSendDelay(), - fallbackScheduler, - chaosScheduler + fallbackScheduler ); } @@ -111,6 +107,17 @@ public KafkaMessageSenders failFastKafkaMessageSenders(FailFastKafkaProducerProp "failFast"); } + @Bean + public ScheduledExecutorService chaosScheduler(KafkaChaosProperties chaosProperties, InstrumentedExecutorServiceFactory executorServiceFactory) { + KafkaChaosProperties.ChaosSchedulerProperties chaosSchedulerProperties = chaosProperties.getChaosScheduler(); + return executorServiceFactory.scheduledExecutorBuilder( + "chaos", + chaosSchedulerProperties.getThreadPoolSize() + ) + .withMonitoringEnabled(chaosSchedulerProperties.isThreadPoolMonitoringEnabled()) + .create(); + } + @Bean(destroyMethod = "close") public KafkaMessageSendersFactory kafkaMessageSendersFactory(KafkaClustersProperties kafkaClustersProperties, KafkaProducerProperties kafkaProducerProperties, @@ -119,9 +126,12 @@ public KafkaMessageSendersFactory kafkaMessageSendersFactory(KafkaClustersProper LocalMessageStorageProperties localMessageStorageProperties, DatacenterNameProvider datacenterNameProvider, BrokerLatencyReporter brokerLatencyReporter, - MetricsFacade metricsFacade) { + MetricsFacade metricsFacade, + @Named("chaosScheduler") ScheduledExecutorService chaosScheduler + ) { KafkaProperties kafkaProperties = kafkaClustersProperties.toKafkaProperties(datacenterNameProvider); List remoteKafkaProperties = kafkaClustersProperties.toRemoteKafkaProperties(datacenterNameProvider); + return new KafkaMessageSendersFactory( kafkaProperties, remoteKafkaProperties, @@ -133,7 +143,8 @@ public KafkaMessageSendersFactory kafkaMessageSendersFactory(KafkaClustersProper topicLoadingProperties.getMetadata().getRetryInterval(), topicLoadingProperties.getMetadata().getThreadPoolSize(), localMessageStorageProperties.getBufferedSizeBytes(), - kafkaProducerProperties.getMetadataMaxAge() + kafkaProducerProperties.getMetadataMaxAge(), + chaosScheduler ); } diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FrontendPublishingConfiguration.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FrontendPublishingConfiguration.java index 69f57beaae..cbb9920840 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FrontendPublishingConfiguration.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/FrontendPublishingConfiguration.java @@ -1,5 +1,6 @@ package pl.allegro.tech.hermes.frontend.config; +import com.codahale.metrics.MetricRegistry; import com.fasterxml.jackson.databind.ObjectMapper; import io.undertow.server.HttpHandler; import jakarta.inject.Named; @@ -11,6 +12,7 @@ import pl.allegro.tech.hermes.domain.topic.preview.MessagePreviewRepository; import pl.allegro.tech.hermes.frontend.cache.topic.TopicsCache; import pl.allegro.tech.hermes.frontend.listeners.BrokerListeners; +import pl.allegro.tech.hermes.frontend.metric.ThroughputRegistry; import pl.allegro.tech.hermes.frontend.producer.BrokerMessageProducer; import pl.allegro.tech.hermes.frontend.publishing.handlers.HandlersChainFactory; import pl.allegro.tech.hermes.frontend.publishing.handlers.ThroughputLimiter; @@ -56,8 +58,13 @@ public HttpHandler httpHandler(TopicsCache topicsCache, MessageErrorProcessor me } @Bean - public ThroughputLimiter throughputLimiter(ThroughputProperties throughputProperties, MetricsFacade metricsFacade) { - return new ThroughputLimiterFactory(throughputProperties, metricsFacade).provide(); + public ThroughputRegistry throughputRegistry(MetricsFacade metricsFacade) { + return new ThroughputRegistry(metricsFacade, new MetricRegistry()); + } + + @Bean + public ThroughputLimiter throughputLimiter(ThroughputProperties throughputProperties, ThroughputRegistry throughputRegistry) { + return new ThroughputLimiterFactory(throughputProperties, throughputRegistry).provide(); } @Bean diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/GraphiteProperties.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/GraphiteProperties.java deleted file mode 100644 index 60e3a7fab2..0000000000 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/GraphiteProperties.java +++ /dev/null @@ -1,41 +0,0 @@ -package pl.allegro.tech.hermes.frontend.config; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import pl.allegro.tech.hermes.common.di.factories.GraphiteParameters; - -@ConfigurationProperties(prefix = "frontend.graphite") -public class GraphiteProperties implements GraphiteParameters { - - private String prefix = "stats.tech.hermes"; - - private String host = "localhost"; - - private int port = 2003; - - @Override - public String getPrefix() { - return prefix; - } - - public void setPrefix(String prefix) { - this.prefix = prefix; - } - - @Override - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - @Override - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } -} diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/MetricRegistryProperties.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/MetricRegistryProperties.java index eceaadc4f8..3e5e71d80f 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/MetricRegistryProperties.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/config/MetricRegistryProperties.java @@ -1,52 +1,14 @@ package pl.allegro.tech.hermes.frontend.config; import org.springframework.boot.context.properties.ConfigurationProperties; -import pl.allegro.tech.hermes.common.di.factories.MetricRegistryParameters; import java.time.Duration; @ConfigurationProperties(prefix = "frontend.metrics.metric-registry") -public class MetricRegistryProperties implements MetricRegistryParameters { - - private boolean zookeeperReporterEnabled = true; - - private boolean graphiteReporterEnabled = false; - - private boolean consoleReporterEnabled = false; +public class MetricRegistryProperties { private Duration counterExpireAfterAccess = Duration.ofHours(72); - private String disabledAttributes = "M15_RATE, M5_RATE, MEAN, MEAN_RATE, MIN, STDDEV"; - - private Duration reportPeriod = Duration.ofSeconds(20); - - @Override - public boolean isZookeeperReporterEnabled() { - return zookeeperReporterEnabled; - } - - public void setZookeeperReporterEnabled(boolean zookeeperReporterEnabled) { - this.zookeeperReporterEnabled = zookeeperReporterEnabled; - } - - @Override - public boolean isGraphiteReporterEnabled() { - return graphiteReporterEnabled; - } - - public void setGraphiteReporterEnabled(boolean graphiteReporterEnabled) { - this.graphiteReporterEnabled = graphiteReporterEnabled; - } - - @Override - public boolean isConsoleReporterEnabled() { - return consoleReporterEnabled; - } - - public void setConsoleReporterEnabled(boolean consoleReporterEnabled) { - this.consoleReporterEnabled = consoleReporterEnabled; - } - public Duration getCounterExpireAfterAccess() { return counterExpireAfterAccess; } @@ -54,22 +16,4 @@ public Duration getCounterExpireAfterAccess() { public void setCounterExpireAfterAccess(Duration counterExpireAfterAccess) { this.counterExpireAfterAccess = counterExpireAfterAccess; } - - @Override - public String getDisabledAttributes() { - return disabledAttributes; - } - - public void setDisabledAttributes(String disabledAttributes) { - this.disabledAttributes = disabledAttributes; - } - - @Override - public Duration getReportPeriod() { - return reportPeriod; - } - - public void setReportPeriod(Duration reportPeriod) { - this.reportPeriod = reportPeriod; - } } diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/metric/CachedTopic.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/metric/CachedTopic.java index 033351b232..9ffb726071 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/metric/CachedTopic.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/metric/CachedTopic.java @@ -10,7 +10,6 @@ import pl.allegro.tech.hermes.metrics.HermesRateMeter; import pl.allegro.tech.hermes.metrics.HermesTimer; import pl.allegro.tech.hermes.metrics.HermesTimerContext; -import pl.allegro.tech.hermes.metrics.counters.MeterBackedHermesCounter; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -36,8 +35,7 @@ public class CachedTopic { private final HermesHistogram topicMessageContentSize; private final HermesHistogram globalMessageContentSize; - private final MeterBackedHermesCounter topicThroughputMeter; - private final MeterBackedHermesCounter globalThroughputMeter; + private final ThroughputMeter throughputMeter; private final HermesCounter topicDuplicatedMessageCounter; @@ -45,13 +43,18 @@ public class CachedTopic { private final Map httpStatusCodesMeters = new ConcurrentHashMap<>(); - public CachedTopic(Topic topic, MetricsFacade metricsFacade, + public CachedTopic(Topic topic, + MetricsFacade metricsFacade, + ThroughputRegistry throughputRegistry, KafkaTopics kafkaTopics) { - this(topic, metricsFacade, kafkaTopics, false); + this(topic, metricsFacade, throughputRegistry, kafkaTopics, false); } - public CachedTopic(Topic topic, MetricsFacade metricsFacade, - KafkaTopics kafkaTopics, boolean blacklisted) { + public CachedTopic(Topic topic, + MetricsFacade metricsFacade, + ThroughputRegistry throughputRegistry, + KafkaTopics kafkaTopics, + boolean blacklisted) { this.topic = topic; this.kafkaTopics = kafkaTopics; this.metricsFacade = metricsFacade; @@ -66,8 +69,7 @@ public CachedTopic(Topic topic, MetricsFacade metricsFacade, globalMessageContentSize = metricsFacade.topics().topicGlobalMessageContentSizeHistogram(); topicMessageContentSize = metricsFacade.topics().topicMessageContentSizeHistogram(topic.getName()); - globalThroughputMeter = metricsFacade.topics().topicGlobalThroughputBytes(); - topicThroughputMeter = metricsFacade.topics().topicThroughputBytes(topic.getName()); + throughputMeter = throughputRegistry.forTopic(topic.getName()); if (Topic.Ack.ALL.equals(topic.getAck())) { globalProducerLatencyTimer = metricsFacade.topics().ackAllGlobalLatency(); @@ -134,8 +136,7 @@ public void incrementPublished(String datacenter) { public void reportMessageContentSize(int size) { topicMessageContentSize.record(size); globalMessageContentSize.record(size); - topicThroughputMeter.increment(size); - globalThroughputMeter.increment(size); + throughputMeter.increment(size); } public void markDelayedProcessing() { @@ -144,7 +145,7 @@ public void markDelayedProcessing() { } public HermesRateMeter getThroughput() { - return topicThroughputMeter; + return throughputMeter; } public void markMessageDuplicated() { diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/metric/ThroughputMeter.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/metric/ThroughputMeter.java new file mode 100644 index 0000000000..3f225b87e0 --- /dev/null +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/metric/ThroughputMeter.java @@ -0,0 +1,36 @@ +package pl.allegro.tech.hermes.frontend.metric; + +import com.codahale.metrics.Meter; +import pl.allegro.tech.hermes.metrics.HermesCounter; +import pl.allegro.tech.hermes.metrics.HermesRateMeter; + +public class ThroughputMeter implements HermesRateMeter { + + private final HermesCounter topicThroughputMetric; + private final HermesCounter globalThroughputMetric; + private final Meter topicMeter; + private final Meter globalMeter; + + public ThroughputMeter( + HermesCounter topicThroughputMetric, + HermesCounter globalThroughputMetric, + Meter topicMeter, + Meter globalMeter) { + this.topicThroughputMetric = topicThroughputMetric; + this.globalThroughputMetric = globalThroughputMetric; + this.topicMeter = topicMeter; + this.globalMeter = globalMeter; + } + + @Override + public double getOneMinuteRate() { + return topicMeter.getOneMinuteRate(); + } + + public void increment(long size) { + this.topicMeter.mark(size); + this.globalMeter.mark(size); + this.topicThroughputMetric.increment(size); + this.globalThroughputMetric.increment(size); + } +} diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/metric/ThroughputRegistry.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/metric/ThroughputRegistry.java new file mode 100644 index 0000000000..ac01b899b6 --- /dev/null +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/metric/ThroughputRegistry.java @@ -0,0 +1,32 @@ +package pl.allegro.tech.hermes.frontend.metric; + +import com.codahale.metrics.Meter; +import com.codahale.metrics.MetricRegistry; +import pl.allegro.tech.hermes.api.TopicName; +import pl.allegro.tech.hermes.common.metric.MetricsFacade; + +public class ThroughputRegistry { + + private final MetricsFacade metricsFacade; + private final MetricRegistry metricRegistry; + private final Meter globalThroughputMeter; + + public ThroughputRegistry(MetricsFacade metricsFacade, MetricRegistry metricRegistry) { + this.metricsFacade = metricsFacade; + this.metricRegistry = metricRegistry; + this.globalThroughputMeter = metricRegistry.meter("globalThroughputMeter"); + } + + public double getGlobalThroughputOneMinuteRate() { + return globalThroughputMeter.getOneMinuteRate(); + } + + public ThroughputMeter forTopic(TopicName topic) { + return new ThroughputMeter( + metricsFacade.topics().topicThroughputBytes(topic), + metricsFacade.topics().topicGlobalThroughputBytes(), + metricRegistry.meter(topic.qualifiedName() + "Throughput"), + globalThroughputMeter + ); + } +} diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/KafkaChaosProperties.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/KafkaChaosProperties.java new file mode 100644 index 0000000000..9d2ebbdd7e --- /dev/null +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/KafkaChaosProperties.java @@ -0,0 +1,40 @@ +package pl.allegro.tech.hermes.frontend.producer.kafka; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "frontend.kafka.chaos") +public class KafkaChaosProperties { + private ChaosSchedulerProperties chaosScheduler = new ChaosSchedulerProperties(); + + public ChaosSchedulerProperties getChaosScheduler() { + return chaosScheduler; + } + + public void setChaosScheduler(ChaosSchedulerProperties chaosScheduler) { + this.chaosScheduler = chaosScheduler; + } + + public static class ChaosSchedulerProperties { + + private int threadPoolSize = 16; + + private boolean threadPoolMonitoringEnabled = false; + + public int getThreadPoolSize() { + return threadPoolSize; + } + + public void setThreadPoolSize(int threadPoolSize) { + this.threadPoolSize = threadPoolSize; + } + + public boolean isThreadPoolMonitoringEnabled() { + return threadPoolMonitoringEnabled; + } + + public void setThreadPoolMonitoringEnabled(boolean threadPoolMonitoringEnabled) { + this.threadPoolMonitoringEnabled = threadPoolMonitoringEnabled; + } + } + +} diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/KafkaMessageSender.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/KafkaMessageSender.java index b9c53dc048..6e00173e48 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/KafkaMessageSender.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/KafkaMessageSender.java @@ -7,7 +7,9 @@ import org.apache.kafka.common.Metric; import org.apache.kafka.common.MetricName; import org.apache.kafka.common.PartitionInfo; +import org.apache.kafka.common.TopicPartition; import org.apache.kafka.common.errors.InterruptException; +import org.apache.kafka.common.record.RecordBatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pl.allegro.tech.hermes.api.Topic; @@ -22,6 +24,9 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.function.ToDoubleFunction; @@ -34,28 +39,64 @@ public class KafkaMessageSender { private final BrokerLatencyReporter brokerLatencyReporter; private final MetricsFacade metricsFacade; private final String datacenter; + private final ScheduledExecutorService chaosScheduler; KafkaMessageSender(Producer kafkaProducer, BrokerLatencyReporter brokerLatencyReporter, MetricsFacade metricsFacade, - String datacenter) { + String datacenter, + ScheduledExecutorService chaosScheduler) { this.producer = kafkaProducer; this.brokerLatencyReporter = brokerLatencyReporter; this.metricsFacade = metricsFacade; this.datacenter = datacenter; + this.chaosScheduler = chaosScheduler; } public String getDatacenter() { return datacenter; } + public void send(ProducerRecord producerRecord, + CachedTopic cachedTopic, + Message message, + Callback callback, + MultiDatacenterMessageProducer.ChaosExperiment experiment) { + if (experiment.enabled()) { + try { + chaosScheduler.schedule(() -> { + if (experiment.completeWithError()) { + var exception = new ChaosException(datacenter, experiment.delayInMillis(), message.getId()); + callback.onCompletion(exceptionalRecordMetadata(cachedTopic), exception); + } else { + send(producerRecord, cachedTopic, message, callback); + } + }, experiment.delayInMillis(), TimeUnit.MILLISECONDS); + } catch (RejectedExecutionException e) { + logger.warn("Failed while scheduling chaos experiment. Sending message to Kafka.", e); + send(producerRecord, cachedTopic, message, callback); + } + } else { + send(producerRecord, cachedTopic, message, callback); + } + } + public void send(ProducerRecord producerRecord, CachedTopic cachedTopic, Message message, Callback callback) { HermesTimerContext timer = cachedTopic.startBrokerLatencyTimer(); Callback meteredCallback = new MeteredCallback(timer, message, cachedTopic, callback); - producer.send(producerRecord, meteredCallback); + try { + producer.send(producerRecord, meteredCallback); + } catch (Exception e) { + callback.onCompletion(exceptionalRecordMetadata(cachedTopic), e); + } + } + + private static RecordMetadata exceptionalRecordMetadata(CachedTopic cachedTopic) { + var tp = new TopicPartition(cachedTopic.getKafkaTopics().getPrimary().name().asString(), RecordMetadata.UNKNOWN_PARTITION); + return new RecordMetadata(tp, -1, -1, RecordBatch.NO_TIMESTAMP, -1, -1); } List loadPartitionMetadataFor(String topic) { diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/KafkaMessageSendersFactory.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/KafkaMessageSendersFactory.java index b03b8bc387..cd10168f3c 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/KafkaMessageSendersFactory.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/KafkaMessageSendersFactory.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; import static org.apache.kafka.clients.CommonClientConfigs.SECURITY_PROTOCOL_CONFIG; import static org.apache.kafka.clients.producer.ProducerConfig.ACKS_CONFIG; @@ -46,6 +47,7 @@ public class KafkaMessageSendersFactory { private final BrokerLatencyReporter brokerLatencyReporter; private final MetricsFacade metricsFacade; private final long bufferedSizeBytes; + private final ScheduledExecutorService chaosScheduler; public KafkaMessageSendersFactory(KafkaParameters kafkaParameters, List remoteKafkaParameters, @@ -57,7 +59,8 @@ public KafkaMessageSendersFactory(KafkaParameters kafkaParameters, Duration retryInterval, int threadPoolSize, long bufferedSizeBytes, - Duration metadataMaxAge) { + Duration metadataMaxAge, + ScheduledExecutorService chaosScheduler) { this.topicMetadataLoadingExecutor = new TopicMetadataLoadingExecutor(topicsCache, retryCount, retryInterval, threadPoolSize); this.localMinInSyncReplicasLoader = new MinInSyncReplicasLoader(localAdminClient, metadataMaxAge); this.bufferedSizeBytes = bufferedSizeBytes; @@ -65,6 +68,7 @@ public KafkaMessageSendersFactory(KafkaParameters kafkaParameters, this.remoteKafkaParameters = remoteKafkaParameters; this.metricsFacade = metricsFacade; this.brokerLatencyReporter = brokerLatencyReporter; + this.chaosScheduler = chaosScheduler; } @@ -123,11 +127,13 @@ private KafkaMessageSender sender(KafkaParameters kafkaParameter props.put(SECURITY_PROTOCOL_CONFIG, kafkaParameters.getAuthenticationProtocol()); props.put(SASL_JAAS_CONFIG, kafkaParameters.getJaasConfig()); } + return new KafkaMessageSender<>( new org.apache.kafka.clients.producer.KafkaProducer<>(props), brokerLatencyReporter, metricsFacade, - kafkaParameters.getDatacenter() + kafkaParameters.getDatacenter(), + chaosScheduler ); } diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/LocalDatacenterMessageProducer.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/LocalDatacenterMessageProducer.java index 94b11793fe..2fc42890c4 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/LocalDatacenterMessageProducer.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/LocalDatacenterMessageProducer.java @@ -26,14 +26,9 @@ public void send(Message message, CachedTopic cachedTopic, final PublishingCallb ProducerRecord producerRecord = messageConverter.convertToProducerRecord(message, cachedTopic.getKafkaTopics().getPrimary().name()); - try { - var producer = kafkaMessageSenders.get(cachedTopic.getTopic()); - Callback wrappedCallback = new SendCallback(message, cachedTopic, callback, producer.getDatacenter()); - producer.send(producerRecord, cachedTopic, message, wrappedCallback); - } catch (Exception e) { - // message didn't get to internal producer buffer and it will not be send to a broker - callback.onUnpublished(message, cachedTopic.getTopic(), e); - } + var producer = kafkaMessageSenders.get(cachedTopic.getTopic()); + Callback wrappedCallback = new SendCallback(message, cachedTopic, callback, producer.getDatacenter()); + producer.send(producerRecord, cachedTopic, message, wrappedCallback); } @Override diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/MultiDatacenterMessageProducer.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/MultiDatacenterMessageProducer.java index b60cccd65d..349380023c 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/MultiDatacenterMessageProducer.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/producer/kafka/MultiDatacenterMessageProducer.java @@ -18,7 +18,9 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadLocalRandom; @@ -37,20 +39,17 @@ public class MultiDatacenterMessageProducer implements BrokerMessageProducer { private final Duration speculativeSendDelay; private final AdminReadinessService adminReadinessService; private final ScheduledExecutorService fallbackScheduler; - private final ScheduledExecutorService chaosScheduler; public MultiDatacenterMessageProducer(KafkaMessageSenders kafkaMessageSenders, AdminReadinessService adminReadinessService, MessageToKafkaProducerRecordConverter messageConverter, Duration speculativeSendDelay, - ScheduledExecutorService fallbackScheduler, - ScheduledExecutorService chaosScheduler) { + ScheduledExecutorService fallbackScheduler) { this.messageConverter = messageConverter; this.kafkaMessageSenders = kafkaMessageSenders; this.speculativeSendDelay = speculativeSendDelay; this.adminReadinessService = adminReadinessService; this.fallbackScheduler = fallbackScheduler; - this.chaosScheduler = chaosScheduler; } @Override @@ -60,86 +59,115 @@ public void send(Message message, CachedTopic cachedTopic, PublishingCallback ca KafkaMessageSender localSender = kafkaMessageSenders.get(cachedTopic.getTopic()); Optional> remoteSender = getRemoteSender(cachedTopic); - final SendCallback sendCallback = remoteSender.isPresent() - ? SendCallback.withFallback(callback) - : SendCallback.withoutFallback(callback); - Map experiments = createChaosExperimentsPerDatacenter(cachedTopic.getTopic()); - fallbackScheduler.schedule(() -> { - if (!sendCallback.sent.get() && remoteSender.isPresent()) { - sendOrScheduleChaosExperiment( - remoteSender.get(), - producerRecord, - sendCallback, - cachedTopic, - message, - experiments.getOrDefault(remoteSender.get().getDatacenter(), ChaosExperiment.DISABLED) - ); - } - }, speculativeSendDelay.toMillis(), TimeUnit.MILLISECONDS); + if (remoteSender.isPresent()) { + sendWithFallback( + localSender, + remoteSender.get(), + producerRecord, + cachedTopic, + message, + experiments, + callback + ); + } else { + sendWithoutFallback( + localSender, + producerRecord, + cachedTopic, + message, + callback + ); + } + } + + private static class SendWithFallbackExecutionContext { + + private final AtomicBoolean fallbackExecuted = new AtomicBoolean(false); + private final AtomicBoolean sent = new AtomicBoolean(false); + private final AtomicInteger tries; + private final ConcurrentHashMap errors; + + private SendWithFallbackExecutionContext() { + this.tries = new AtomicInteger(2); + this.errors = new ConcurrentHashMap<>(2); + } + + public boolean tryTransitionToFallback() { + return fallbackExecuted.compareAndSet(false, true) && !sent.get(); + } + + boolean tryTransitionToUnpublished(String datacenter, Exception exception) { + errors.put(datacenter, exception); + return tries.decrementAndGet() == 0; + } + + public boolean tryTransitionToFirstSent() { + return sent.compareAndSet(false, true); + } + } + + /* + We first try to send message to local DC. If the local send fails we perform 'immediate' fallback to remote DC. + + Additionally, we schedule a 'speculative' fallback to remote DC to execute after 'speculativeSendDelay' elapses. + Speculative fallback decreases publication latency but may result in messages being duplicated across DCs. - sendOrScheduleChaosExperiment( - localSender, + If local DC send succeeds or fails before 'speculativeSendDelay' elapses we try to cancel the 'speculative' fallback if + it has not been executed yet. We guarantee that only one fallback executes - either 'immediate' or 'speculative'. + */ + private void sendWithFallback(KafkaMessageSender localSender, + KafkaMessageSender remoteSender, + ProducerRecord producerRecord, + CachedTopic cachedTopic, + Message message, + Map experiments, + PublishingCallback publishingCallback) { + + SendWithFallbackExecutionContext context = new SendWithFallbackExecutionContext(); + + FallbackRunnable fallback = new FallbackRunnable( + remoteSender, producerRecord, - sendCallback, cachedTopic, message, - experiments.getOrDefault(localSender.getDatacenter(), ChaosExperiment.DISABLED) + experiments.getOrDefault(remoteSender.getDatacenter(), ChaosExperiment.DISABLED), + publishingCallback, + context ); - } - private void send(KafkaMessageSender sender, - ProducerRecord producerRecord, - SendCallback callback, - CachedTopic cachedTopic, - Message message) { - String datacenter = sender.getDatacenter(); + Future speculativeFallback; try { - sender.send(producerRecord, cachedTopic, message, new DCAwareCallback( - message, - cachedTopic, - datacenter, - callback)); - } catch (Exception e) { - // message didn't get to internal producer buffer and it will not be sent to a broker - callback.onUnpublished(message, cachedTopic, datacenter, e); + speculativeFallback = fallbackScheduler.schedule(fallback, speculativeSendDelay.toMillis(), TimeUnit.MILLISECONDS); + } catch (RejectedExecutionException rejectedExecutionException) { + logger.warn("Failed to run schedule fallback for message: {}, topic: {}", message, cachedTopic.getQualifiedName(), rejectedExecutionException); + speculativeFallback = CompletableFuture.completedFuture(null); } - } - private void sendOrScheduleChaosExperiment(KafkaMessageSender sender, - ProducerRecord producerRecord, - SendCallback callback, - CachedTopic cachedTopic, - Message message, - ChaosExperiment experiment) { - if (experiment.enabled()) { - scheduleChaosExperiment(experiment, sender, producerRecord, callback, cachedTopic, message); - } else { - send(sender, producerRecord, callback, cachedTopic, message); - } + localSender.send( + producerRecord, + cachedTopic, + message, + new FallbackAwareLocalSendCallback( + message, cachedTopic, localSender.getDatacenter(), + context, publishingCallback, fallback, speculativeFallback + ), + experiments.getOrDefault(localSender.getDatacenter(), ChaosExperiment.DISABLED) + ); } - private void scheduleChaosExperiment(ChaosExperiment experiment, - KafkaMessageSender sender, - ProducerRecord producerRecord, - SendCallback callback, - CachedTopic cachedTopic, - Message message) { - try { - chaosScheduler.schedule(() -> { - if (experiment.completeWithError()) { - var datacenter = sender.getDatacenter(); - var exception = new ChaosException(datacenter, experiment.delayInMillis(), message.getId()); - callback.onUnpublished(message, cachedTopic, datacenter, exception); - } else { - send(sender, producerRecord, callback, cachedTopic, message); - } - }, experiment.delayInMillis(), TimeUnit.MILLISECONDS); - } catch (RejectedExecutionException e) { - logger.warn("Failed while scheduling chaos experiment. Sending message to Kafka.", e); - send(sender, producerRecord, callback, cachedTopic, message); - } + private void sendWithoutFallback(KafkaMessageSender sender, + ProducerRecord producerRecord, + CachedTopic cachedTopic, + Message message, + PublishingCallback callback) { + sender.send( + producerRecord, + cachedTopic, + message, + new LocalSendCallback(message, cachedTopic, sender.getDatacenter(), callback) + ); } private Map createChaosExperimentsPerDatacenter(Topic topic) { @@ -185,7 +213,7 @@ private ChaosExperiment createChaosExperimentForDatacenter(ChaosPolicy policy, b return new ChaosExperiment(true, policy.completeWithError(), delayMillis); } - private record ChaosExperiment(boolean enabled, boolean completeWithError, long delayInMillis) { + public record ChaosExperiment(boolean enabled, boolean completeWithError, long delayInMillis) { private static final ChaosExperiment DISABLED = new ChaosExperiment(false, false, 0); @@ -198,53 +226,132 @@ private Optional> getRemoteSender(CachedTopic .findFirst(); } - private record DCAwareCallback(Message message, CachedTopic cachedTopic, String datacenter, - SendCallback callback) implements Callback { + private record RemoteSendCallback(Message message, CachedTopic cachedTopic, + String datacenter, PublishingCallback callback, + SendWithFallbackExecutionContext state) implements Callback { @Override public void onCompletion(RecordMetadata metadata, Exception exception) { if (exception == null) { - callback.onPublished(message, cachedTopic, datacenter); + callback.onEachPublished(message, cachedTopic.getTopic(), datacenter); + if (state.tryTransitionToFirstSent()) { + callback.onPublished(message, cachedTopic.getTopic()); + } else { + cachedTopic.markMessageDuplicated(); + } } else { - callback.onUnpublished(message, cachedTopic, datacenter, exception); + if (state.tryTransitionToUnpublished(datacenter, exception)) { + callback.onUnpublished(message, cachedTopic.getTopic(), new MultiDCPublishException(state.errors)); + } } } } - private static class SendCallback { + private class FallbackAwareLocalSendCallback implements Callback { + private final Message message; + private final CachedTopic cachedTopic; + private final String datacenter; private final PublishingCallback callback; - private final AtomicBoolean sent = new AtomicBoolean(false); - private final AtomicInteger tries; - private final ConcurrentHashMap errors; - - private SendCallback(PublishingCallback callback, int tries) { + private final FallbackRunnable fallback; + private final Future speculativeFallback; + private final SendWithFallbackExecutionContext state; + + private FallbackAwareLocalSendCallback(Message message, CachedTopic cachedTopic, String datacenter, + SendWithFallbackExecutionContext state, + PublishingCallback callback, + FallbackRunnable fallback, Future speculativeFallback) { + this.message = message; + this.cachedTopic = cachedTopic; + this.datacenter = datacenter; this.callback = callback; - this.tries = new AtomicInteger(tries); - this.errors = new ConcurrentHashMap<>(tries); + this.fallback = fallback; + this.speculativeFallback = speculativeFallback; + this.state = state; } - static SendCallback withFallback(PublishingCallback callback) { - return new SendCallback(callback, 2); + @Override + public void onCompletion(RecordMetadata metadata, Exception exception) { + if (exception == null) { + cancelSpeculativeFallback(); + callback.onEachPublished(message, cachedTopic.getTopic(), datacenter); + if (state.tryTransitionToFirstSent()) { + callback.onPublished(message, cachedTopic.getTopic()); + } else { + cachedTopic.markMessageDuplicated(); + } + } else { + if (state.tryTransitionToUnpublished(datacenter, exception)) { + callback.onUnpublished(message, cachedTopic.getTopic(), new MultiDCPublishException(state.errors)); + } else { + fallback(); + } + } } - static SendCallback withoutFallback(PublishingCallback callback) { - return new SendCallback(callback, 1); + private void fallback() { + try { + speculativeFallback.cancel(false); + fallbackScheduler.execute(fallback); + } catch (RejectedExecutionException rejectedExecutionException) { + logger.warn("Failed to run immediate fallback for message: {}, topic: {}", message, cachedTopic.getQualifiedName(), rejectedExecutionException); + } } - private void onUnpublished(Message message, CachedTopic cachedTopic, String datacenter, Exception exception) { - errors.put(datacenter, exception); - if (tries.decrementAndGet() == 0) { - callback.onUnpublished(message, cachedTopic.getTopic(), new MultiDCPublishException(errors)); - } + private void cancelSpeculativeFallback() { + speculativeFallback.cancel(false); } + } - private void onPublished(Message message, CachedTopic cachedTopic, String datacenter) { - callback.onEachPublished(message, cachedTopic.getTopic(), datacenter); - if (sent.compareAndSet(false, true)) { - callback.onPublished(message, cachedTopic.getTopic()); + private record LocalSendCallback(Message message, CachedTopic cachedTopic, String datacenter, + PublishingCallback callback) implements Callback { + + @Override + public void onCompletion(RecordMetadata metadata, Exception exception) { + if (exception != null) { + callback.onUnpublished(message, cachedTopic.getTopic(), exception); } else { - cachedTopic.markMessageDuplicated(); + callback.onEachPublished(message, cachedTopic.getTopic(), datacenter); + callback.onPublished(message, cachedTopic.getTopic()); + } + } + } + + private class FallbackRunnable implements Runnable { + private final KafkaMessageSender remoteSender; + private final ProducerRecord producerRecord; + private final CachedTopic cachedTopic; + private final Message message; + private final ChaosExperiment experiment; + private final PublishingCallback callback; + private final SendWithFallbackExecutionContext context; + + public FallbackRunnable(KafkaMessageSender remoteSender, + ProducerRecord producerRecord, + CachedTopic cachedTopic, + Message message, + ChaosExperiment experiment, + PublishingCallback callback, + SendWithFallbackExecutionContext context + ) { + this.remoteSender = remoteSender; + this.producerRecord = producerRecord; + this.cachedTopic = cachedTopic; + this.message = message; + this.experiment = experiment; + this.callback = callback; + this.context = context; + } + + public void run() { + if (context.tryTransitionToFallback()) { + remoteSender.send( + producerRecord, + cachedTopic, + message, + new RemoteSendCallback(message, cachedTopic, remoteSender.getDatacenter(), callback, context), + experiment + ); } } } diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/handlers/PublishingHandler.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/handlers/PublishingHandler.java index 9f795fb3b5..aa20a45520 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/handlers/PublishingHandler.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/handlers/PublishingHandler.java @@ -35,6 +35,9 @@ public void handleRequest(HttpServerExchange exchange) { try { handle(exchange); } catch (RuntimeException e) { + AttachmentContent attachment = exchange.getAttachment(AttachmentContent.KEY); + MessageState messageState = attachment.getMessageState(); + messageState.setErrorInSendingToKafka(); messageErrorProcessor.sendAndLog(exchange, "Exception while publishing message to a broker.", e); } }); diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/handlers/ThroughputLimiterFactory.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/handlers/ThroughputLimiterFactory.java index aae4d09ff2..da0abba8a5 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/handlers/ThroughputLimiterFactory.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/handlers/ThroughputLimiterFactory.java @@ -3,7 +3,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import pl.allegro.tech.hermes.common.metric.MetricsFacade; +import pl.allegro.tech.hermes.frontend.metric.ThroughputRegistry; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; @@ -15,13 +15,13 @@ public class ThroughputLimiterFactory { private final ThroughputParameters throughputParameters; - private final MetricsFacade metricsFacade; + private final ThroughputRegistry throughputRegistry; private enum ThroughputLimiterType { UNLIMITED, FIXED, DYNAMIC } - public ThroughputLimiterFactory(ThroughputParameters throughputParameters, MetricsFacade metricsFacade) { + public ThroughputLimiterFactory(ThroughputParameters throughputParameters, ThroughputRegistry throughputRegistry) { this.throughputParameters = throughputParameters; - this.metricsFacade = metricsFacade; + this.throughputRegistry = throughputRegistry; } public ThroughputLimiter provide() { @@ -37,7 +37,7 @@ public ThroughputLimiter provide() { throughputParameters.getDynamicDesired(), throughputParameters.getDynamicIdle(), throughputParameters.getDynamicCheckInterval(), - metricsFacade.topics().topicGlobalThroughputBytes(), + throughputRegistry::getGlobalThroughputOneMinuteRate, getExecutor()); default: throw new IllegalArgumentException("Unknown throughput limiter type."); diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/message/MessageContentTypeEnforcer.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/message/MessageContentTypeEnforcer.java index ad1d7c7913..72dd78f57d 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/message/MessageContentTypeEnforcer.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/message/MessageContentTypeEnforcer.java @@ -1,7 +1,7 @@ package pl.allegro.tech.hermes.frontend.publishing.message; import org.apache.avro.Schema; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import pl.allegro.tech.hermes.api.Topic; import pl.allegro.tech.hermes.common.message.wrapper.UnsupportedContentTypeException; import tech.allegro.schema.json2avro.converter.JsonAvroConverter; diff --git a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/preview/MessagePreviewFactory.java b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/preview/MessagePreviewFactory.java index 1087d45e28..fae6b9205e 100644 --- a/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/preview/MessagePreviewFactory.java +++ b/hermes-frontend/src/main/java/pl/allegro/tech/hermes/frontend/publishing/preview/MessagePreviewFactory.java @@ -1,6 +1,6 @@ package pl.allegro.tech.hermes.frontend.publishing.preview; -import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang3.ArrayUtils; import pl.allegro.tech.hermes.domain.topic.preview.MessagePreview; import pl.allegro.tech.hermes.frontend.publishing.message.Message; import pl.allegro.tech.hermes.frontend.publishing.message.MessageToJsonConverter; diff --git a/hermes-frontend/src/main/resources/application-integration.yaml b/hermes-frontend/src/main/resources/application-integration.yaml index 4af762bba7..1ab55e4739 100644 --- a/hermes-frontend/src/main/resources/application-integration.yaml +++ b/hermes-frontend/src/main/resources/application-integration.yaml @@ -17,12 +17,6 @@ frontend: http2Enabled: true handlers: idleTimeout: 2000ms - metrics: - metric-registry: - graphiteReporterEnabled: true - reportPeriod: 1s - graphite: - port: 18023 zookeeper: clusters: - diff --git a/hermes-frontend/src/main/resources/application-local.yaml b/hermes-frontend/src/main/resources/application-local.yaml index c98dc5d41d..1c78837c87 100644 --- a/hermes-frontend/src/main/resources/application-local.yaml +++ b/hermes-frontend/src/main/resources/application-local.yaml @@ -8,11 +8,6 @@ frontend: clusters: - datacenter: "dc" brokerList: "localhost:9092" - graphite: - host: "localhost" - metrics: - metric-registry: - graphiteReporterEnabled: true schema: cache: refreshAfterWrite: 1m diff --git a/hermes-frontend/src/test/groovy/pl/allegro/tech/hermes/frontend/producer/kafka/LocalDatacenterMessageProducerIntegrationTest.groovy b/hermes-frontend/src/test/groovy/pl/allegro/tech/hermes/frontend/producer/kafka/LocalDatacenterMessageProducerIntegrationTest.groovy index edbab24478..46b1913121 100644 --- a/hermes-frontend/src/test/groovy/pl/allegro/tech/hermes/frontend/producer/kafka/LocalDatacenterMessageProducerIntegrationTest.groovy +++ b/hermes-frontend/src/test/groovy/pl/allegro/tech/hermes/frontend/producer/kafka/LocalDatacenterMessageProducerIntegrationTest.groovy @@ -1,7 +1,6 @@ package pl.allegro.tech.hermes.frontend.producer.kafka import com.codahale.metrics.MetricRegistry -import com.jayway.awaitility.Awaitility import io.micrometer.core.instrument.simple.SimpleMeterRegistry import org.apache.commons.lang3.tuple.ImmutablePair import org.apache.kafka.clients.admin.AdminClient @@ -10,6 +9,7 @@ import org.apache.kafka.clients.consumer.KafkaConsumer import org.apache.kafka.clients.consumer.OffsetAndMetadata import org.apache.kafka.clients.producer.KafkaProducer import org.apache.kafka.common.TopicPartition +import org.awaitility.Awaitility import org.testcontainers.containers.KafkaContainer import org.testcontainers.containers.wait.strategy.Wait import org.testcontainers.spock.Testcontainers @@ -17,7 +17,6 @@ import pl.allegro.tech.hermes.api.* import pl.allegro.tech.hermes.common.kafka.ConsumerGroupId import pl.allegro.tech.hermes.common.kafka.JsonToAvroMigrationKafkaNamesMapper import pl.allegro.tech.hermes.common.kafka.KafkaNamesMapper -import pl.allegro.tech.hermes.common.metric.HermesMetrics import pl.allegro.tech.hermes.common.metric.MetricsFacade import pl.allegro.tech.hermes.frontend.config.HTTPHeadersProperties import pl.allegro.tech.hermes.frontend.config.KafkaHeaderNameProperties @@ -26,7 +25,6 @@ import pl.allegro.tech.hermes.frontend.metric.CachedTopic import pl.allegro.tech.hermes.frontend.producer.BrokerLatencyReporter import pl.allegro.tech.hermes.frontend.publishing.avro.AvroMessage import pl.allegro.tech.hermes.frontend.server.CachedTopicsTestHelper -import pl.allegro.tech.hermes.metrics.PathsCompiler import pl.allegro.tech.hermes.test.helper.avro.AvroUser import pl.allegro.tech.hermes.test.helper.builder.TopicBuilder import pl.allegro.tech.hermes.test.helper.containers.ImageTags @@ -34,6 +32,8 @@ import spock.lang.Shared import spock.lang.Specification import java.time.Duration +import java.util.concurrent.Executors +import java.util.concurrent.ScheduledExecutorService import java.util.stream.Collectors import static java.util.Collections.emptyList @@ -82,13 +82,13 @@ class LocalDatacenterMessageProducerIntegrationTest extends Specification { KafkaHeaderNameProperties kafkaHeaderNameProperties = new KafkaHeaderNameProperties() @Shared - String datacenter = "dc"; + String datacenter = "dc" @Shared - MetricsFacade metricsFacade = new MetricsFacade( - new SimpleMeterRegistry(), - new HermesMetrics(new MetricRegistry(), new PathsCompiler("")) - ) + ScheduledExecutorService chaosScheduler = Executors.newSingleThreadScheduledExecutor(); + + @Shared + MetricsFacade metricsFacade = new MetricsFacade(new SimpleMeterRegistry()) def setupSpec() { kafkaContainer.start() @@ -111,8 +111,8 @@ class LocalDatacenterMessageProducerIntegrationTest extends Specification { topicMetadataLoadingExecutor, minInSyncReplicasLoader, new KafkaMessageSenders.Tuple( - new KafkaMessageSender(leaderConfirms, brokerLatencyReporter, metricsFacade, datacenter), - new KafkaMessageSender(everyoneConfirms, brokerLatencyReporter, metricsFacade, datacenter) + new KafkaMessageSender(leaderConfirms, brokerLatencyReporter, metricsFacade, datacenter, chaosScheduler), + new KafkaMessageSender(everyoneConfirms, brokerLatencyReporter, metricsFacade, datacenter, chaosScheduler) ), emptyList() ) @@ -163,7 +163,7 @@ class LocalDatacenterMessageProducerIntegrationTest extends Specification { private static def createTestSubscription(Topic topic, String subscriptionName) { Subscription.create(topic.getQualifiedName(), subscriptionName, null, Subscription.State.PENDING, "test", [:], false, null, null, - null, ContentType.JSON, DeliveryType.SERIAL, [], SubscriptionMode.ANYCAST, [], null, null, false, false, false + null, ContentType.JSON, DeliveryType.SERIAL, [], SubscriptionMode.ANYCAST, [], null, null, false, false, 0, false, false ) } diff --git a/hermes-frontend/src/test/groovy/pl/allegro/tech/hermes/frontend/producer/kafka/MultiDatacenterMessageProducerTest.groovy b/hermes-frontend/src/test/groovy/pl/allegro/tech/hermes/frontend/producer/kafka/MultiDatacenterMessageProducerTest.groovy new file mode 100644 index 0000000000..596105bc7a --- /dev/null +++ b/hermes-frontend/src/test/groovy/pl/allegro/tech/hermes/frontend/producer/kafka/MultiDatacenterMessageProducerTest.groovy @@ -0,0 +1,279 @@ +package pl.allegro.tech.hermes.frontend.producer.kafka + +import org.apache.kafka.clients.producer.Callback +import org.apache.kafka.clients.producer.ProducerRecord +import pl.allegro.tech.hermes.api.Topic +import pl.allegro.tech.hermes.frontend.metric.CachedTopic +import pl.allegro.tech.hermes.frontend.publishing.PublishingCallback +import pl.allegro.tech.hermes.frontend.publishing.message.JsonMessage +import pl.allegro.tech.hermes.frontend.publishing.message.Message +import pl.allegro.tech.hermes.frontend.readiness.AdminReadinessService +import pl.allegro.tech.hermes.frontend.server.CachedTopicsTestHelper +import pl.allegro.tech.hermes.test.helper.builder.TopicBuilder +import spock.lang.Specification +import spock.util.concurrent.PollingConditions + +import java.time.Duration +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.ScheduledExecutorService +import java.util.concurrent.atomic.AtomicInteger + +import static java.util.Collections.emptyMap + +class MultiDatacenterMessageProducerTest extends Specification { + ScheduledExecutorService fallbackScheduler = Executors.newSingleThreadScheduledExecutor(); + ExecutorService testExecutor = Executors.newSingleThreadExecutor(); + + + Duration speculativeSendDelay = Duration.ofMillis(250); + Message message = new JsonMessage('id', [2] as byte[], 0L, null, emptyMap()); + + private static final String localDC = "LOCAL" + private static final String remoteDC = "REMOTE" + + class VerificationCallback implements PublishingCallback { + AtomicInteger onUnpublished = new AtomicInteger(0) + AtomicInteger onPublished = new AtomicInteger(0) + AtomicInteger publishedToLocal = new AtomicInteger(0) + AtomicInteger publishedToRemote = new AtomicInteger(0) + volatile String exception = "" + + @Override + void onUnpublished(Message message, Topic topic, Exception exception) { + onUnpublished.incrementAndGet(); + this.exception = exception; + } + + @Override + void onPublished(Message message, Topic topic) { + onPublished.incrementAndGet(); + } + + @Override + void onEachPublished(Message message, Topic topic, String datacenter) { + if (datacenter == localDC) { + publishedToLocal.incrementAndGet() + } else if (datacenter == remoteDC) { + publishedToRemote.incrementAndGet() + } + } + } + + def "should send to local DC only if the send is successful before speculativeSendDelay elapses"() { + given: + CachedTopic cachedTopic = CachedTopicsTestHelper.cachedTopic(TopicBuilder.topicWithRandomName().build()) + + def localSender = successfulSender(localDC) + def remoteSender = successfulSender(remoteDC) + + def producer = producer(localSender, remoteSender) + + PublishingCallback callback = new VerificationCallback(); + + when: + testExecutor.execute { producer.send(message, cachedTopic, callback) } + + then: + // wait until speculative send delay elapses + Thread.sleep(speculativeSendDelay.plusMillis(200).toMillis()) + callback.publishedToLocal.get() == 1 + callback.publishedToRemote.get() == 0 + callback.onPublished.get() == 1 + callback.onUnpublished.get() == 0 + + } + + def "should send to remote DC if local DC fails"() { + given: + CachedTopic cachedTopic = CachedTopicsTestHelper.cachedTopic(TopicBuilder.topicWithRandomName().build()) + + def localSender = failingSender(localDC) + def remoteSender = successfulSender(remoteDC) + + def producer = producer(localSender, remoteSender) + + + PublishingCallback callback = new VerificationCallback(); + + when: + testExecutor.execute { producer.send(message, cachedTopic, callback) } + + then: + new PollingConditions(timeout: 10).eventually { + callback.publishedToLocal.get() == 0 + callback.publishedToRemote.get() == 1 + callback.onPublished.get() == 1 + callback.onUnpublished.get() == 0 + } + } + + def "should send to remote DC when local does not respond before speculativeSendDelay elapses"() { + given: + CachedTopic cachedTopic = CachedTopicsTestHelper.cachedTopic(TopicBuilder.topicWithRandomName().build()) + + def localSender = stuckLocalSender() + def remoteSender = successfulSender(remoteDC) + + def producer = producer(localSender, remoteSender) + + PublishingCallback callback = new VerificationCallback(); + + when: + def start = System.currentTimeMillis() + testExecutor.execute { producer.send(message, cachedTopic, callback) } + + then: + new PollingConditions(timeout: 10).eventually { + callback.publishedToLocal.get() == 0 + callback.publishedToRemote.get() == 1 + callback.onPublished.get() == 1 + callback.onUnpublished.get() == 0 + System.currentTimeMillis() - start > speculativeSendDelay.toMillis() + } + } + + def "should publish to local DC and remote DC when local send is slower than speculativeSendDelay but it eventually succeeds"() { + given: + CachedTopic cachedTopic = CachedTopicsTestHelper.cachedTopic(TopicBuilder.topicWithRandomName().build()) + + def localSender = delayedSender(localDC, speculativeSendDelay.plusMillis(100).toMillis()) + def remoteSender = successfulSender(remoteDC) + + def producer = producer(localSender, remoteSender) + + PublishingCallback callback = new VerificationCallback(); + + when: + testExecutor.execute { producer.send(message, cachedTopic, callback) } + + then: + new PollingConditions(timeout: 10).eventually { + callback.publishedToLocal.get() == 1 + callback.publishedToRemote.get() == 1 + callback.onPublished.get() == 1 + callback.onUnpublished.get() == 0 + } + } + + def "should invoke onUnpublished when both DCs fail"() { + given: + CachedTopic cachedTopic = CachedTopicsTestHelper.cachedTopic(TopicBuilder.topicWithRandomName().build()) + + def localSender = failingSender(localDC, "network error") + def remoteSender = failingSender(remoteDC, "not leader or follower") + + def producer = producer(localSender, remoteSender) + + + PublishingCallback callback = new VerificationCallback(); + + when: + testExecutor.execute { producer.send(message, cachedTopic, callback) } + + then: + new PollingConditions(timeout: 10).eventually { + callback.publishedToLocal.get() == 0 + callback.publishedToRemote.get() == 0 + callback.onPublished.get() == 0 + callback.onUnpublished.get() == 1 + callback.exception.contains("[LOCAL]: RuntimeException: network error") + callback.exception.contains("[REMOTE]: RuntimeException: not leader or follower") + } + } + + def "should publish to remote DC once when both scheduled fallback (after speculativeSendDelay) and immediate fallback are run"() { + given: + CachedTopic cachedTopic = CachedTopicsTestHelper.cachedTopic(TopicBuilder.topicWithRandomName().build()) + + def localSender = delayedFailingSender(localDC, speculativeSendDelay.toMillis() + 5) + def remoteSender = successfulSender(remoteDC) + + def producer = producer(localSender, remoteSender) + + PublishingCallback callback = new VerificationCallback() + + when: + testExecutor.execute { producer.send(message, cachedTopic, callback) } + + then: + Thread.sleep(speculativeSendDelay.toMillis() + 100) + callback.publishedToLocal.get() == 0 + callback.publishedToRemote.get() == 1 + callback.onPublished.get() == 1 + callback.onUnpublished.get() == 0 + } + + + KafkaMessageSender stuckLocalSender() { + return Mock(KafkaMessageSender) { + getDatacenter() >> localDC + } + } + + KafkaMessageSender delayedSender(String sender, long delayMillis) { + return Mock(KafkaMessageSender) { + getDatacenter() >> sender + send(*_) >> (arguments) -> { + Thread.sleep(delayMillis) + callback(arguments).onCompletion(null, null) + } + } + } + + KafkaMessageSender delayedFailingSender(String sender, long delayMillis, String exceptionMsg = "fail") { + return Mock(KafkaMessageSender) { + getDatacenter() >> sender + send(*_) >> (arguments) -> { + Thread.sleep(delayMillis) + callback(arguments).onCompletion(null, new RuntimeException(exceptionMsg)) + } + } + } + + KafkaMessageSender failingSender(String sender, String exceptionMsg = "fail") { + return Mock(KafkaMessageSender) { + getDatacenter() >> sender + send(*_) >> { + arguments -> callback(arguments).onCompletion(null, new RuntimeException(exceptionMsg)) + } + } + } + + KafkaMessageSender successfulSender(String sender) { + return Mock(KafkaMessageSender) { + getDatacenter() >> sender + send(*_) >> { + arguments -> callback(arguments).onCompletion(null, null) + } + } + } + + // callback argument from pl.allegro.tech.hermes.frontend.producer.kafka.KafkaMessageSender#send + Callback callback(arguments) { + return (arguments[3] as Callback) + } + + MultiDatacenterMessageProducer producer(KafkaMessageSender localSender, KafkaMessageSender remoteSender) { + MessageToKafkaProducerRecordConverter messageConverter = Mock(MessageToKafkaProducerRecordConverter) { + convertToProducerRecord(*_) >> new ProducerRecord("topic", new byte[]{0x0}, new byte[]{0x0}) + } + + def adminReadinessService = Mock(AdminReadinessService) { + isDatacenterReady(_) >> true + } + + KafkaMessageSenders senders = new KafkaMessageSenders( + Mock(TopicMetadataLoadingExecutor), + Mock(MinInSyncReplicasLoader), + new KafkaMessageSenders.Tuple( + localSender, localSender + ), + [new KafkaMessageSenders.Tuple(remoteSender, remoteSender)] + ) + + return new MultiDatacenterMessageProducer( + senders, adminReadinessService, messageConverter, speculativeSendDelay, fallbackScheduler + ) + } +} diff --git a/hermes-frontend/src/test/groovy/pl/allegro/tech/hermes/frontend/publishing/metric/ThroughputRegistryTest.groovy b/hermes-frontend/src/test/groovy/pl/allegro/tech/hermes/frontend/publishing/metric/ThroughputRegistryTest.groovy new file mode 100644 index 0000000000..b5d5d397a0 --- /dev/null +++ b/hermes-frontend/src/test/groovy/pl/allegro/tech/hermes/frontend/publishing/metric/ThroughputRegistryTest.groovy @@ -0,0 +1,67 @@ +package pl.allegro.tech.hermes.frontend.publishing.metric + +import com.codahale.metrics.MetricRegistry +import io.micrometer.core.instrument.simple.SimpleMeterRegistry +import org.assertj.core.api.Assertions +import org.awaitility.Awaitility +import pl.allegro.tech.hermes.api.Topic +import pl.allegro.tech.hermes.common.metric.MetricsFacade +import pl.allegro.tech.hermes.frontend.metric.ThroughputMeter +import pl.allegro.tech.hermes.frontend.metric.ThroughputRegistry +import spock.lang.Shared +import spock.lang.Specification + +import java.time.Duration + +import static pl.allegro.tech.hermes.test.helper.builder.TopicBuilder.topic + +class ThroughputRegistryTest extends Specification { + @Shared + Topic topicA = topic("group.topicA").build() + @Shared + Topic topicB = topic("group.topicB").build() + @Shared + Topic topicC = topic("group.topicC").build(); + + private final MetricsFacade metricsFacade = new MetricsFacade(new SimpleMeterRegistry()); + private final ThroughputRegistry throughputRegistry = new ThroughputRegistry(metricsFacade, new MetricRegistry()) + + def "topic throughput should be preserved for instances of the same topic"() { + given: "throughput meter for a topic with recorded value" + ThroughputMeter meter = throughputRegistry.forTopic(topicA.getName()) + assert meter.oneMinuteRate == 0.0d + + meter.increment(1024) + + when: "new throughput meter is obtained for the same topic" + meter = throughputRegistry.forTopic(topicA.getName()) + + then: "throughput is preserved" + Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted { + Assertions.assertThat(meter.oneMinuteRate).isGreaterThan(0.0d) + } + } + + def "global throughput should be shared for all topics"() { + given: "given throughput meters for two topics" + ThroughputMeter topicBMeter = throughputRegistry.forTopic(topicB.getName()) + ThroughputMeter topicCMeter = throughputRegistry.forTopic(topicC.getName()) + assert topicBMeter.oneMinuteRate == 0.0d + assert topicCMeter.oneMinuteRate == 0.0d + + when: "throughput for both meters is recorded" + topicBMeter.increment(1024) + topicCMeter.increment(1024) + + then: "global throughput is a sum of topic throughput" + Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted { + def topicAValue = topicBMeter.oneMinuteRate + def topicBValue = topicCMeter.oneMinuteRate + def globalValue = throughputRegistry.globalThroughputOneMinuteRate + Assertions.assertThat(topicAValue).isGreaterThan(0.0d) + Assertions.assertThat(topicBValue).isGreaterThan(0.0d) + Assertions.assertThat(globalValue).isGreaterThan(topicAValue) + } + } + +} diff --git a/hermes-frontend/src/test/groovy/pl/allegro/tech/hermes/frontend/server/CachedTopicsTestHelper.groovy b/hermes-frontend/src/test/groovy/pl/allegro/tech/hermes/frontend/server/CachedTopicsTestHelper.groovy index 08cd79fc9f..a76d3d4eaa 100644 --- a/hermes-frontend/src/test/groovy/pl/allegro/tech/hermes/frontend/server/CachedTopicsTestHelper.groovy +++ b/hermes-frontend/src/test/groovy/pl/allegro/tech/hermes/frontend/server/CachedTopicsTestHelper.groovy @@ -7,26 +7,23 @@ import pl.allegro.tech.hermes.api.Topic import pl.allegro.tech.hermes.common.kafka.KafkaTopic import pl.allegro.tech.hermes.common.kafka.KafkaTopicName import pl.allegro.tech.hermes.common.kafka.KafkaTopics -import pl.allegro.tech.hermes.common.metric.HermesMetrics import pl.allegro.tech.hermes.common.metric.MetricsFacade import pl.allegro.tech.hermes.frontend.metric.CachedTopic -import pl.allegro.tech.hermes.metrics.PathsCompiler +import pl.allegro.tech.hermes.frontend.metric.ThroughputRegistry import pl.allegro.tech.hermes.test.helper.builder.TopicBuilder class CachedTopicsTestHelper { - static HermesMetrics hermesMetrics = new HermesMetrics( - new MetricRegistry(), new PathsCompiler("localhost")) - - static MetricsFacade micrometerHermesMetrics = new MetricsFacade(new SimpleMeterRegistry(), hermesMetrics) + static MetricsFacade micrometerHermesMetrics = new MetricsFacade(new SimpleMeterRegistry()) + static ThroughputRegistry registry = new ThroughputRegistry(micrometerHermesMetrics, new MetricRegistry()) static CachedTopic cachedTopic(String name) { def kafkaTopics = new KafkaTopics(new KafkaTopic(KafkaTopicName.valueOf(name), ContentType.JSON)) - return new CachedTopic(TopicBuilder.topic(name).build(), micrometerHermesMetrics, kafkaTopics) + return new CachedTopic(TopicBuilder.topic(name).build(), micrometerHermesMetrics, registry, kafkaTopics) } static CachedTopic cachedTopic(Topic topic) { def kafkaTopics = new KafkaTopics(new KafkaTopic(KafkaTopicName.valueOf(topic.qualifiedName), ContentType.JSON)) - return new CachedTopic(topic, micrometerHermesMetrics, kafkaTopics) + return new CachedTopic(topic, micrometerHermesMetrics, registry, kafkaTopics) } } diff --git a/hermes-frontend/src/test/java/pl/allegro/tech/hermes/frontend/buffer/BackupMessagesLoaderTest.java b/hermes-frontend/src/test/java/pl/allegro/tech/hermes/frontend/buffer/BackupMessagesLoaderTest.java index d4a8f5de74..528b0a0e38 100644 --- a/hermes-frontend/src/test/java/pl/allegro/tech/hermes/frontend/buffer/BackupMessagesLoaderTest.java +++ b/hermes-frontend/src/test/java/pl/allegro/tech/hermes/frontend/buffer/BackupMessagesLoaderTest.java @@ -35,8 +35,8 @@ import static java.time.LocalDateTime.now; import static java.time.ZoneOffset.UTC; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -71,9 +71,8 @@ public void setUp() { tempDir = Files.createTempDir(); Timer micrometerTimer = new SimpleMeterRegistry().timer("broker-latency"); - com.codahale.metrics.Timer graphiteTimer = new com.codahale.metrics.Timer(); when(cachedTopic.getTopic()).thenReturn(topic); - when(cachedTopic.startBrokerLatencyTimer()).thenReturn(HermesTimerContext.from(micrometerTimer, graphiteTimer)); + when(cachedTopic.startBrokerLatencyTimer()).thenReturn(HermesTimerContext.from(micrometerTimer)); when(topicsCache.getTopic(topic.getQualifiedName())).thenReturn(Optional.of(cachedTopic)); when(producer.isTopicAvailable(cachedTopic)).thenReturn(true); } diff --git a/hermes-frontend/src/test/java/pl/allegro/tech/hermes/frontend/producer/kafka/LocalDatacenterMessageProducerTest.java b/hermes-frontend/src/test/java/pl/allegro/tech/hermes/frontend/producer/kafka/LocalDatacenterMessageProducerTest.java index 9d0abf3232..3866830892 100644 --- a/hermes-frontend/src/test/java/pl/allegro/tech/hermes/frontend/producer/kafka/LocalDatacenterMessageProducerTest.java +++ b/hermes-frontend/src/test/java/pl/allegro/tech/hermes/frontend/producer/kafka/LocalDatacenterMessageProducerTest.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.frontend.producer.kafka; -import com.codahale.metrics.MetricRegistry; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.apache.kafka.clients.admin.AdminClient; import org.apache.kafka.clients.producer.MockProducer; @@ -11,34 +10,34 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import pl.allegro.tech.hermes.api.Topic; import pl.allegro.tech.hermes.common.kafka.HTTPHeadersPropagationAsKafkaHeadersProperties; import pl.allegro.tech.hermes.common.kafka.KafkaNamesMapper; import pl.allegro.tech.hermes.common.kafka.NamespaceKafkaNamesMapper; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; import pl.allegro.tech.hermes.frontend.cache.topic.TopicsCache; import pl.allegro.tech.hermes.frontend.config.HTTPHeadersProperties; import pl.allegro.tech.hermes.frontend.config.KafkaHeaderNameProperties; import pl.allegro.tech.hermes.frontend.config.SchemaProperties; import pl.allegro.tech.hermes.frontend.metric.CachedTopic; +import pl.allegro.tech.hermes.frontend.metric.ThroughputRegistry; import pl.allegro.tech.hermes.frontend.producer.BrokerLatencyReporter; import pl.allegro.tech.hermes.frontend.publishing.PublishingCallback; import pl.allegro.tech.hermes.frontend.publishing.message.JsonMessage; import pl.allegro.tech.hermes.frontend.publishing.message.Message; -import pl.allegro.tech.hermes.metrics.PathsCompiler; import java.time.Duration; import java.util.List; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.atomic.AtomicBoolean; import static com.google.common.base.Charsets.UTF_8; -import static com.jayway.awaitility.Awaitility.await; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import static pl.allegro.tech.hermes.test.helper.builder.TopicBuilder.topic; @RunWith(MockitoJUnitRunner.class) @@ -53,16 +52,16 @@ public class LocalDatacenterMessageProducerTest { private static final Message MESSAGE = new JsonMessage(MESSAGE_ID, CONTENT, TIMESTAMP, PARTITION_KEY, emptyMap()); private final ByteArraySerializer serializer = new ByteArraySerializer(); - @Mock - private HermesMetrics hermesMetrics = new HermesMetrics(new MetricRegistry(), new PathsCompiler("")); - private final MetricsFacade metricsFacade = new MetricsFacade(new SimpleMeterRegistry(), hermesMetrics); + private final MetricsFacade metricsFacade = new MetricsFacade(new SimpleMeterRegistry()); private final BrokerLatencyReporter brokerLatencyReporter = new BrokerLatencyReporter(false, metricsFacade, Duration.ZERO, Executors.newSingleThreadExecutor()); + private final ScheduledExecutorService chaosScheduler = Executors.newSingleThreadScheduledExecutor(); + private final MockProducer leaderConfirmsProducer = new MockProducer<>(true, serializer, serializer); private final MockProducer everyoneConfirmProducer = new MockProducer<>(true, serializer, serializer); - private final KafkaMessageSender leaderConfirmsProduceWrapper = new KafkaMessageSender<>(leaderConfirmsProducer, brokerLatencyReporter, metricsFacade, datacenter); - private final KafkaMessageSender everyoneConfirmsProduceWrapper = new KafkaMessageSender<>(everyoneConfirmProducer, brokerLatencyReporter, metricsFacade, datacenter); + private final KafkaMessageSender leaderConfirmsProduceWrapper = new KafkaMessageSender<>(leaderConfirmsProducer, brokerLatencyReporter, metricsFacade, datacenter, chaosScheduler); + private final KafkaMessageSender everyoneConfirmsProduceWrapper = new KafkaMessageSender<>(everyoneConfirmProducer, brokerLatencyReporter, metricsFacade, datacenter, chaosScheduler); private final KafkaHeaderNameProperties kafkaHeaderNameProperties = new KafkaHeaderNameProperties(); private final HTTPHeadersPropagationAsKafkaHeadersProperties httpHeadersPropagationAsKafkaHeadersProperties = @@ -91,9 +90,12 @@ public class LocalDatacenterMessageProducerTest { private final SchemaProperties schemaProperties = new SchemaProperties(); + @Mock + private ThroughputRegistry throughputRegistry; + @Before public void before() { - cachedTopic = new CachedTopic(TOPIC, metricsFacade, kafkaNamesMapper.toKafkaTopics(TOPIC)); + cachedTopic = new CachedTopic(TOPIC, metricsFacade, throughputRegistry, kafkaNamesMapper.toKafkaTopics(TOPIC)); MessageToKafkaProducerRecordConverter messageConverter = new MessageToKafkaProducerRecordConverter(kafkaHeaderFactory, schemaProperties.isIdHeaderEnabled()); producer = new LocalDatacenterMessageProducer(kafkaMessageSenders, messageConverter); @@ -160,7 +162,7 @@ public void onEachPublished(Message message, Topic topic, String datacenter) { public void shouldUseEveryoneConfirmProducerForTopicWithAckAll() { //given Topic topic = topic("group.all").withAck(Topic.Ack.ALL).build(); - CachedTopic cachedTopic = new CachedTopic(topic, metricsFacade, + CachedTopic cachedTopic = new CachedTopic(topic, metricsFacade, throughputRegistry, kafkaNamesMapper.toKafkaTopics(topic)); //when diff --git a/hermes-management/build.gradle b/hermes-management/build.gradle index f1105eadcb..f6b966dbdd 100644 --- a/hermes-management/build.gradle +++ b/hermes-management/build.gradle @@ -15,27 +15,25 @@ dependencies { api group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: versions.spring api group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: versions.spring api group: 'org.springframework.boot', name: 'spring-boot-starter-jersey', version: versions.spring - implementation group: 'net.sf.jopt-simple', name: 'jopt-simple', version: '4.8' + implementation group: 'net.sf.jopt-simple', name: 'jopt-simple', version: '5.0.4' implementation group: 'org.glassfish.jersey.ext', name: 'jersey-mvc-freemarker', version: versions.jersey - implementation (group: 'io.swagger', name: 'swagger-jersey2-jaxrs', version: '1.6.3') { + implementation (group: 'io.swagger', name: 'swagger-jersey2-jaxrs', version: '1.6.14') { exclude group: 'javax.validation', module: 'validation-api' } implementation group: 'org.apache.kafka', name: 'kafka-clients', version: versions.kafka - implementation group: 'commons-codec', name: 'commons-codec', version: '1.9' - implementation (group: 'com.github.fge', name: 'json-schema-validator', version: '2.2.6') { - exclude group: 'net.sf.jopt-simple' - } + implementation group: 'commons-codec', name: 'commons-codec', version: '1.16.1' + implementation group: 'com.github.java-json-tools', name: 'json-schema-validator', version: '2.2.14' implementation group: 'commons-jxpath', name: 'commons-jxpath', version: '1.3' - implementation group: 'org.apache.httpcomponents.client5', name: 'httpclient5', version: '5.2.1' + implementation group: 'org.apache.httpcomponents.client5', name: 'httpclient5', version: '5.3.1' - api group: 'org.javers', name: 'javers-core', version: '5.2.5' + api group: 'org.javers', name: 'javers-core', version: '7.4.2' implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: versions.jackson - implementation group: 'commons-io', name: 'commons-io', version: '2.6' + implementation group: 'commons-io', name: 'commons-io', version: '2.16.1' testImplementation project(':hermes-test-helper') testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: versions.spring diff --git a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/api/auth/AllowAllSecurityProvider.java b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/api/auth/AllowAllSecurityProvider.java index 214e99c5fd..395429516c 100644 --- a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/api/auth/AllowAllSecurityProvider.java +++ b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/api/auth/AllowAllSecurityProvider.java @@ -2,7 +2,7 @@ import jakarta.ws.rs.container.ContainerRequestContext; import jakarta.ws.rs.core.SecurityContext; -import org.apache.commons.lang.NotImplementedException; +import org.apache.commons.lang3.NotImplementedException; import java.security.Principal; diff --git a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/ExternalMonitoringConfiguration.java b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/ExternalMonitoringConfiguration.java index accd325bf2..ed3148d5b3 100644 --- a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/ExternalMonitoringConfiguration.java +++ b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/ExternalMonitoringConfiguration.java @@ -13,9 +13,6 @@ import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; -import pl.allegro.tech.hermes.management.infrastructure.graphite.CachingGraphiteClient; -import pl.allegro.tech.hermes.management.infrastructure.graphite.GraphiteClient; -import pl.allegro.tech.hermes.management.infrastructure.graphite.RestTemplateGraphiteClient; import pl.allegro.tech.hermes.management.infrastructure.prometheus.CachingPrometheusClient; import pl.allegro.tech.hermes.management.infrastructure.prometheus.PrometheusClient; import pl.allegro.tech.hermes.management.infrastructure.prometheus.RestTemplatePrometheusClient; @@ -28,20 +25,6 @@ @Configuration public class ExternalMonitoringConfiguration { - @Bean - @ConditionalOnProperty(value = "graphite.client.enabled", havingValue = "true") - public GraphiteClient graphiteClient(@Qualifier("monitoringRestTemplate") RestTemplate graphiteRestTemplate, - GraphiteMonitoringMetricsProperties graphiteClientProperties) { - RestTemplateGraphiteClient underlyingGraphiteClient = - new RestTemplateGraphiteClient(graphiteRestTemplate, URI.create(graphiteClientProperties.getExternalMonitoringUrl())); - return new CachingGraphiteClient( - underlyingGraphiteClient, - systemTicker(), - graphiteClientProperties.getCacheTtlSeconds(), - graphiteClientProperties.getCacheSize() - ); - } - @Bean @ConditionalOnProperty(value = "prometheus.client.enabled", havingValue = "true") public VictoriaMetricsMetricsProvider prometheusMetricsProvider(PrometheusClient prometheusClient, @@ -53,10 +36,10 @@ public VictoriaMetricsMetricsProvider prometheusMetricsProvider(PrometheusClient @Bean @ConditionalOnProperty(value = "prometheus.client.enabled", havingValue = "true") - public PrometheusClient prometheusClient(@Qualifier("monitoringRestTemplate") RestTemplate graphiteRestTemplate, + public PrometheusClient prometheusClient(@Qualifier("monitoringRestTemplate") RestTemplate monitoringRestTemplate, PrometheusMonitoringClientProperties clientProperties) { RestTemplatePrometheusClient underlyingPrometheusClient = - new RestTemplatePrometheusClient(graphiteRestTemplate, URI.create(clientProperties.getExternalMonitoringUrl())); + new RestTemplatePrometheusClient(monitoringRestTemplate, URI.create(clientProperties.getExternalMonitoringUrl())); return new CachingPrometheusClient( underlyingPrometheusClient, systemTicker(), diff --git a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/GraphiteMonitoringMetricsProperties.java b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/GraphiteMonitoringMetricsProperties.java deleted file mode 100644 index 4ae837902f..0000000000 --- a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/GraphiteMonitoringMetricsProperties.java +++ /dev/null @@ -1,14 +0,0 @@ -package pl.allegro.tech.hermes.management.config; - -public class GraphiteMonitoringMetricsProperties extends ExternalMonitoringClientProperties { - - private String prefix = "stats.tech.hermes"; - - public String getPrefix() { - return prefix; - } - - public void setPrefix(String prefix) { - this.prefix = prefix; - } -} diff --git a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/ManagementConfiguration.java b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/ManagementConfiguration.java index 8277843789..c6945f814c 100644 --- a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/ManagementConfiguration.java +++ b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/ManagementConfiguration.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.management.config; -import com.codahale.metrics.MetricRegistry; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.InjectableValues; @@ -15,7 +14,6 @@ import org.springframework.context.annotation.Configuration; import pl.allegro.tech.hermes.api.Topic; import pl.allegro.tech.hermes.common.clock.ClockFactory; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; import pl.allegro.tech.hermes.common.util.InetAddressInstanceIdResolver; import pl.allegro.tech.hermes.common.util.InstanceIdResolver; @@ -55,12 +53,6 @@ public ObjectMapper objectMapper() { return mapper; } - @Bean - @ConditionalOnMissingBean - public MetricRegistry metricRegistry() { - return new MetricRegistry(); - } - @Bean public InstanceIdResolver instanceIdResolver() { return new InetAddressInstanceIdResolver(); @@ -72,14 +64,8 @@ public PathsCompiler pathsCompiler(InstanceIdResolver instanceIdResolver) { } @Bean - public HermesMetrics hermesMetrics(MetricRegistry metricRegistry, - PathsCompiler pathsCompiler) { - return new HermesMetrics(metricRegistry, pathsCompiler); - } - - @Bean - public MetricsFacade micrometerHermesMetrics(MeterRegistry meterRegistry, HermesMetrics hermesMetrics) { - return new MetricsFacade(meterRegistry, hermesMetrics); + public MetricsFacade micrometerHermesMetrics(MeterRegistry meterRegistry) { + return new MetricsFacade(meterRegistry); } @Bean diff --git a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/MonitoringClientPropertiesConfiguration.java b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/MonitoringClientPropertiesConfiguration.java index a67745dc33..ed4b733b0d 100644 --- a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/MonitoringClientPropertiesConfiguration.java +++ b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/config/MonitoringClientPropertiesConfiguration.java @@ -11,12 +11,6 @@ */ @Configuration public class MonitoringClientPropertiesConfiguration { - @Bean - @ConfigurationProperties("graphite.client") - @ConditionalOnProperty(value = "graphite.client.enabled", havingValue = "true") - public GraphiteMonitoringMetricsProperties graphiteMonitoringClientProperties() { - return new GraphiteMonitoringMetricsProperties(); - } @Bean @ConfigurationProperties("prometheus.client") diff --git a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/domain/filtering/FilteringService.java b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/domain/filtering/FilteringService.java index 0cf4e1a8f0..09cb1148f9 100644 --- a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/domain/filtering/FilteringService.java +++ b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/domain/filtering/FilteringService.java @@ -1,7 +1,7 @@ package pl.allegro.tech.hermes.management.domain.filtering; import org.apache.avro.Schema; -import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.springframework.stereotype.Component; import pl.allegro.tech.hermes.api.MessageFiltersVerificationInput; import pl.allegro.tech.hermes.api.MessageFiltersVerificationResult; diff --git a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/graphite/CachingGraphiteClient.java b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/graphite/CachingGraphiteClient.java deleted file mode 100644 index aeae87869d..0000000000 --- a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/graphite/CachingGraphiteClient.java +++ /dev/null @@ -1,62 +0,0 @@ -package pl.allegro.tech.hermes.management.infrastructure.graphite; - -import com.google.common.base.Ticker; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import pl.allegro.tech.hermes.api.MetricDecimalValue; -import pl.allegro.tech.hermes.management.infrastructure.metrics.MonitoringMetricsContainer; - -import java.util.Map; -import java.util.concurrent.ExecutionException; - -import static com.google.common.collect.Iterables.toArray; -import static java.util.Arrays.asList; -import static java.util.Arrays.stream; -import static java.util.Collections.singleton; -import static java.util.concurrent.TimeUnit.SECONDS; -import static java.util.function.Function.identity; -import static java.util.stream.Collectors.toMap; - -public class CachingGraphiteClient implements GraphiteClient { - - private final GraphiteClient underlyingGraphiteClient; - private final LoadingCache graphiteMetricsCache; - - public CachingGraphiteClient(GraphiteClient underlyingGraphiteClient, Ticker ticker, long cacheTtlInSeconds, long cacheSize) { - this.underlyingGraphiteClient = underlyingGraphiteClient; - this.graphiteMetricsCache = CacheBuilder.newBuilder() - .ticker(ticker) - .expireAfterWrite(cacheTtlInSeconds, SECONDS) - .maximumSize(cacheSize) - .build(new GraphiteMetricsCacheLoader()); - } - - @Override - public MonitoringMetricsContainer readMetrics(String... metricPaths) { - try { - Map graphiteMetrics = graphiteMetricsCache.getAll(asList(metricPaths)); - return MonitoringMetricsContainer.initialized(graphiteMetrics); - } catch (ExecutionException e) { - // should never happen because the loader does not throw any checked exceptions - throw new RuntimeException(e); - } - } - - private class GraphiteMetricsCacheLoader extends CacheLoader { - @Override - public MetricDecimalValue load(String metricPath) { - return loadAll(singleton(metricPath)).get(metricPath); - } - - @Override - public Map loadAll(Iterable metricPaths) { - String[] metricPathsArray = toArray(metricPaths, String.class); - MonitoringMetricsContainer metricsContainer = underlyingGraphiteClient.readMetrics(metricPathsArray); - return stream(metricPathsArray).collect(toMap( - identity(), - metricsContainer::metricValue - )); - } - } -} \ No newline at end of file diff --git a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/graphite/GraphiteClient.java b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/graphite/GraphiteClient.java deleted file mode 100644 index 489991f76f..0000000000 --- a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/graphite/GraphiteClient.java +++ /dev/null @@ -1,8 +0,0 @@ -package pl.allegro.tech.hermes.management.infrastructure.graphite; - -import pl.allegro.tech.hermes.management.infrastructure.metrics.MonitoringMetricsContainer; - -public interface GraphiteClient { - - MonitoringMetricsContainer readMetrics(String... metricPaths); -} diff --git a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/graphite/GraphiteResponse.java b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/graphite/GraphiteResponse.java deleted file mode 100644 index 4b5fedfbe5..0000000000 --- a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/graphite/GraphiteResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -package pl.allegro.tech.hermes.management.infrastructure.graphite; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -public class GraphiteResponse { - - private final String target; - private final List> datapoints; - - @JsonCreator - public GraphiteResponse( - @JsonProperty("target") String target, - @JsonProperty("datapoints") List> datapoints - ) { - this.target = target; - this.datapoints = datapoints; - } - - public String getTarget() { - return target; - } - - public List> getDatapoints() { - return datapoints; - } -} diff --git a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/graphite/RestTemplateGraphiteClient.java b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/graphite/RestTemplateGraphiteClient.java index baad2da445..e69de29bb2 100644 --- a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/graphite/RestTemplateGraphiteClient.java +++ b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/graphite/RestTemplateGraphiteClient.java @@ -1,95 +0,0 @@ -package pl.allegro.tech.hermes.management.infrastructure.graphite; - -import com.google.common.base.Strings; -import jakarta.ws.rs.core.UriBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; -import pl.allegro.tech.hermes.api.MetricDecimalValue; -import pl.allegro.tech.hermes.management.infrastructure.metrics.MonitoringMetricsContainer; - -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.util.List; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.apache.commons.lang.exception.ExceptionUtils.getRootCauseMessage; - -public class RestTemplateGraphiteClient implements GraphiteClient { - - private static final Logger logger = LoggerFactory.getLogger(RestTemplateGraphiteClient.class); - - private static final ParameterizedTypeReference> GRAPHITE_RESPONSE_TYPE = - new ParameterizedTypeReference<>() { - }; - - private static final String DEFAULT_VALUE = "0.0"; - - private static final String TARGET_PARAM = "target"; - - private final URI graphiteUri; - - private final RestTemplate restTemplate; - - public RestTemplateGraphiteClient(RestTemplate restTemplate, URI graphiteUri) { - this.restTemplate = restTemplate; - this.graphiteUri = graphiteUri; - } - - @Override - public MonitoringMetricsContainer readMetrics(String... metricPaths) { - try { - MonitoringMetricsContainer response = MonitoringMetricsContainer.createEmpty(); - queryGraphite(metricPaths).forEach(metric -> response.addMetricValue(metric.getTarget(), getFirstValue(metric))); - return response; - } catch (Exception exception) { - logger.warn("Unable to read from Graphite: {}", getRootCauseMessage(exception)); - return MonitoringMetricsContainer.unavailable(); - } - } - - private MetricDecimalValue getFirstValue(GraphiteResponse graphiteResponse) { - checkArgument(hasDatapoints(graphiteResponse), "Graphite format changed. Reexamine implementation."); - - String firstNotNullValue = DEFAULT_VALUE; - for (List datapoint : graphiteResponse.getDatapoints()) { - if (datapointValid(datapoint)) { - firstNotNullValue = datapoint.get(0); - break; - } - } - return MetricDecimalValue.of(firstNotNullValue); - } - - private boolean datapointValid(List value) { - return !value.isEmpty() && !Strings.isNullOrEmpty(value.get(0)) && !"null".equals(value.get(0)); - } - - private boolean hasDatapoints(GraphiteResponse graphiteResponse) { - return !graphiteResponse.getDatapoints().isEmpty() && !graphiteResponse.getDatapoints().get(0).isEmpty(); - } - - private List queryGraphite(String... queries) throws UnsupportedEncodingException { - UriBuilder builder = UriBuilder.fromUri(graphiteUri) - .path("render") - .queryParam("from", "-5minutes") - .queryParam("until", "-1minutes") - .queryParam("format", "json"); - - for (String query : queries) { - builder.queryParam(TARGET_PARAM, query); - } - - ResponseEntity> response = restTemplate.exchange( - builder.build(), - HttpMethod.GET, - HttpEntity.EMPTY, - GRAPHITE_RESPONSE_TYPE - ); - return response.getBody(); - } -} diff --git a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/metrics/HybridSubscriptionMetricsRepository.java b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/metrics/HybridSubscriptionMetricsRepository.java index 8b82e66be7..712a5bba17 100644 --- a/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/metrics/HybridSubscriptionMetricsRepository.java +++ b/hermes-management/src/main/java/pl/allegro/tech/hermes/management/infrastructure/metrics/HybridSubscriptionMetricsRepository.java @@ -14,7 +14,8 @@ import java.util.function.Supplier; -import static org.apache.commons.lang.exception.ExceptionUtils.getRootCauseMessage; +import static org.apache.commons.lang3.exception.ExceptionUtils.getRootCauseMessage; + @Component public class HybridSubscriptionMetricsRepository implements SubscriptionMetricsRepository { diff --git a/hermes-management/src/test/groovy/pl/allegro/tech/hermes/management/infrastructure/graphite/CachingGraphiteClientTest.groovy b/hermes-management/src/test/groovy/pl/allegro/tech/hermes/management/infrastructure/graphite/CachingGraphiteClientTest.groovy deleted file mode 100644 index cde1f26f27..0000000000 --- a/hermes-management/src/test/groovy/pl/allegro/tech/hermes/management/infrastructure/graphite/CachingGraphiteClientTest.groovy +++ /dev/null @@ -1,54 +0,0 @@ -package pl.allegro.tech.hermes.management.infrastructure.graphite - -import pl.allegro.tech.hermes.management.infrastructure.metrics.MonitoringMetricsContainer -import pl.allegro.tech.hermes.test.helper.cache.FakeTicker -import spock.lang.Specification -import spock.lang.Subject - -import java.time.Duration - -import static pl.allegro.tech.hermes.api.MetricDecimalValue.of - -class CachingGraphiteClientTest extends Specification { - static final CACHE_TTL_IN_SECONDS = 30 - static final CACHE_SIZE = 100_000 - static final CACHE_TTL = Duration.ofSeconds(CACHE_TTL_IN_SECONDS) - - def underlyingClient = Mock(GraphiteClient) - def ticker = new FakeTicker() - - @Subject - def cachingClient = new CachingGraphiteClient(underlyingClient, ticker, CACHE_TTL_IN_SECONDS, CACHE_SIZE) - - def "should return metrics from the underlying client"() { - given: - underlyingClient.readMetrics("metric_1", "metric_2") >> MonitoringMetricsContainer.initialized([metric_1: of("1"), metric_2: of("2")]) - - when: - def metrics = cachingClient.readMetrics("metric_1", "metric_2") - - then: - metrics.metricValue("metric_1") == of("1") - metrics.metricValue("metric_2") == of("2") - } - - def "should return metrics from cache while TTL has not expired"() { - when: - cachingClient.readMetrics("metric_1", "metric_2") - ticker.advance(CACHE_TTL.minusSeconds(1)) - cachingClient.readMetrics("metric_1", "metric_2") - - then: - 1 * underlyingClient.readMetrics("metric_1", "metric_2") >> MonitoringMetricsContainer.initialized([metric_1: of("1"), metric_2: of("2")]) - } - - def "should get metrics from the underlying client after TTL expires"() { - when: - cachingClient.readMetrics("metric_1", "metric_2") - ticker.advance(CACHE_TTL.plusSeconds(1)) - cachingClient.readMetrics("metric_1", "metric_2") - - then: - 2 * underlyingClient.readMetrics("metric_1", "metric_2") >> MonitoringMetricsContainer.initialized([metric_1: of("1"), metric_2: of("2")]) - } -} diff --git a/hermes-management/src/test/groovy/pl/allegro/tech/hermes/management/infrastructure/graphite/RestTemplateGraphiteClientTest.groovy b/hermes-management/src/test/groovy/pl/allegro/tech/hermes/management/infrastructure/graphite/RestTemplateGraphiteClientTest.groovy deleted file mode 100644 index e73c9be9ef..0000000000 --- a/hermes-management/src/test/groovy/pl/allegro/tech/hermes/management/infrastructure/graphite/RestTemplateGraphiteClientTest.groovy +++ /dev/null @@ -1,101 +0,0 @@ -package pl.allegro.tech.hermes.management.infrastructure.graphite - -import com.github.tomakehurst.wiremock.client.WireMock -import com.github.tomakehurst.wiremock.junit.WireMockRule -import jakarta.ws.rs.core.MediaType -import org.junit.Rule -import org.springframework.web.client.RestTemplate -import pl.allegro.tech.hermes.management.infrastructure.metrics.MonitoringMetricsContainer -import pl.allegro.tech.hermes.test.helper.util.Ports -import spock.lang.Specification - -import static pl.allegro.tech.hermes.api.MetricDecimalValue.of - -class RestTemplateGraphiteClientTest extends Specification { - - private static final int GRAPHITE_HTTP_PORT = Ports.nextAvailable() - - @Rule - WireMockRule wireMockRule = new WireMockRule(GRAPHITE_HTTP_PORT) - - private RestTemplateGraphiteClient client - - void setup() { - RestTemplate restTemplate = new RestTemplate(); - client = new RestTemplateGraphiteClient(restTemplate, URI.create("http://localhost:$GRAPHITE_HTTP_PORT")); - } - - def "should get metrics for path"() { - given: - mockGraphite([ - [ metric: 'metric1', data: ['10'] ], - [ metric: 'metric2', data: ['20'] ] - ]) - - when: - MonitoringMetricsContainer metrics = client.readMetrics("metric1", "metric2") - - then: - metrics.metricValue("metric1") == of("10") - metrics.metricValue("metric2") == of("20") - } - - def "should return default value when metric has no value"() { - given: - mockGraphite([[ metric: 'metric', data: [null] ]]) - - when: - MonitoringMetricsContainer metrics = client.readMetrics("metric"); - - then: - metrics.metricValue("metric1") == of("0.0") - } - - def "should return first notnull value"() { - given: - mockGraphite([ - [ metric: 'metric', data: [null, null, '13'] ], - ]) - - when: - MonitoringMetricsContainer metrics = client.readMetrics("metric"); - - then: - metrics.metricValue("metric") == of("13") - } - - def "should properly encode metric query strings"() { - given: - mockGraphite([ - [ metric: 'sumSeries%28stats.tech.hermes.%2A.m1_rate%29', data: ['13'] ], - ]) - - when: - MonitoringMetricsContainer metrics = client.readMetrics('sumSeries(stats.tech.hermes.*.m1_rate)'); - - then: - metrics.metricValue('sumSeries%28stats.tech.hermes.%2A.m1_rate%29') == of("13") - } - - private void mockGraphite(List queries) { - String targetParams = queries.collect({ "target=$it.metric" }).join('&') - String response = '[' + queries.collect({ jsonResponse(it.metric, it.data) }).join(',') + ']' - - mockGraphite(targetParams, response) - } - - private void mockGraphite(String targetParams, String jsonResponse) { - WireMock.stubFor(WireMock.get(WireMock.urlEqualTo(String.format("/render?from=-5minutes&until=-1minutes&format=json&%s", targetParams))) - .willReturn(WireMock.aResponse() - .withStatus(200) - .withHeader("Content-Type", MediaType.APPLICATION_JSON) - .withBody(jsonResponse))); - } - - private String jsonResponse(String query, List datapoints) { - long timestamp = System.currentTimeSeconds() - String datapointsString = datapoints.collect({ "[$it, $timestamp]" }).join(',') - return '{"target": "' + query + '", "datapoints": [' + datapointsString + '], "tags": []}' - } - -} diff --git a/hermes-management/src/test/groovy/pl/allegro/tech/hermes/management/infrastructure/kafka/service/KafkaConsumerGroupManagerSpec.groovy b/hermes-management/src/test/groovy/pl/allegro/tech/hermes/management/infrastructure/kafka/service/KafkaConsumerGroupManagerSpec.groovy index 4a0283d5a5..b43834d8ad 100644 --- a/hermes-management/src/test/groovy/pl/allegro/tech/hermes/management/infrastructure/kafka/service/KafkaConsumerGroupManagerSpec.groovy +++ b/hermes-management/src/test/groovy/pl/allegro/tech/hermes/management/infrastructure/kafka/service/KafkaConsumerGroupManagerSpec.groovy @@ -22,6 +22,7 @@ import pl.allegro.tech.hermes.common.kafka.KafkaNamesMapper import pl.allegro.tech.hermes.management.config.kafka.KafkaProperties import pl.allegro.tech.hermes.management.domain.subscription.ConsumerGroupManager import pl.allegro.tech.hermes.test.helper.builder.TopicBuilder +import pl.allegro.tech.hermes.test.helper.containers.ImageTags import spock.lang.Shared import spock.lang.Specification @@ -38,7 +39,7 @@ class KafkaConsumerGroupManagerSpec extends Specification { OutputCaptureRule output = new OutputCaptureRule() @Shared - KafkaContainer kafkaContainer = new KafkaContainer() + KafkaContainer kafkaContainer = new KafkaContainer(ImageTags.confluentImagesTag()) @Shared String containerId @@ -167,7 +168,7 @@ class KafkaConsumerGroupManagerSpec extends Specification { private static def createTestSubscription(Topic topic, String subscriptionName) { Subscription.create(topic.getQualifiedName(), subscriptionName, null, Subscription.State.PENDING, "test", [:], false, null, null, - null, ContentType.JSON, DeliveryType.SERIAL, [], SubscriptionMode.ANYCAST, [], null, null, false, false, false + null, ContentType.JSON, DeliveryType.SERIAL, [], SubscriptionMode.ANYCAST, [], null, null, false, false, 0, false, false ) } diff --git a/hermes-metrics/build.gradle b/hermes-metrics/build.gradle index 867742ae82..f06e7f39ad 100644 --- a/hermes-metrics/build.gradle +++ b/hermes-metrics/build.gradle @@ -3,8 +3,8 @@ plugins { } dependencies { - api group: 'io.dropwizard.metrics', name: 'metrics-graphite', version: versions.dropwizard_metrics - api group: 'commons-lang', name: 'commons-lang', version: '2.6' + api group: 'io.dropwizard.metrics', name: 'metrics-core', version: versions.dropwizard_metrics + api group: 'org.apache.commons', name: 'commons-text', version: '1.12.0' api group: 'io.micrometer', name: 'micrometer-core', version: versions.micrometer_metrics testImplementation group: 'org.spockframework', name: 'spock-core', version: versions.spock diff --git a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/DefaultHermesHistogram.java b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/DefaultHermesHistogram.java index 33e8d9b14e..ffc1573d94 100644 --- a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/DefaultHermesHistogram.java +++ b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/DefaultHermesHistogram.java @@ -1,23 +1,20 @@ package pl.allegro.tech.hermes.metrics; +import io.micrometer.core.instrument.DistributionSummary; + public class DefaultHermesHistogram implements HermesHistogram { - private final io.micrometer.core.instrument.DistributionSummary micrometerHistogram; - private final com.codahale.metrics.Histogram graphiteHistogram; + private final DistributionSummary micrometerHistogram; - private DefaultHermesHistogram(io.micrometer.core.instrument.DistributionSummary micrometerHistogram, - com.codahale.metrics.Histogram graphiteHistogram) { + private DefaultHermesHistogram(io.micrometer.core.instrument.DistributionSummary micrometerHistogram) { this.micrometerHistogram = micrometerHistogram; - this.graphiteHistogram = graphiteHistogram; } - public static DefaultHermesHistogram of(io.micrometer.core.instrument.DistributionSummary micrometerHistogram, - com.codahale.metrics.Histogram graphiteHistogram) { - return new DefaultHermesHistogram(micrometerHistogram, graphiteHistogram); + public static DefaultHermesHistogram of(io.micrometer.core.instrument.DistributionSummary micrometerHistogram) { + return new DefaultHermesHistogram(micrometerHistogram); } @Override public void record(long value) { micrometerHistogram.record(value); - graphiteHistogram.update(value); } } diff --git a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/HermesTimer.java b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/HermesTimer.java index 9b518afd6e..8102c31c94 100644 --- a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/HermesTimer.java +++ b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/HermesTimer.java @@ -1,21 +1,19 @@ package pl.allegro.tech.hermes.metrics; +import io.micrometer.core.instrument.Timer; + public class HermesTimer { - private final io.micrometer.core.instrument.Timer micrometerTimer; - private final com.codahale.metrics.Timer graphiteTimer; + private final Timer micrometerTimer; - private HermesTimer(io.micrometer.core.instrument.Timer micrometerTimer, - com.codahale.metrics.Timer graphiteTimer) { + private HermesTimer(Timer micrometerTimer) { this.micrometerTimer = micrometerTimer; - this.graphiteTimer = graphiteTimer; } - public static HermesTimer from(io.micrometer.core.instrument.Timer micrometerTimer, - com.codahale.metrics.Timer graphiteTimer) { - return new HermesTimer(micrometerTimer, graphiteTimer); + public static HermesTimer from(io.micrometer.core.instrument.Timer micrometerTimer) { + return new HermesTimer(micrometerTimer); } public HermesTimerContext time() { - return HermesTimerContext.from(micrometerTimer, graphiteTimer); + return HermesTimerContext.from(micrometerTimer); } } \ No newline at end of file diff --git a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/HermesTimerContext.java b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/HermesTimerContext.java index b3a39a349b..65bb85d157 100644 --- a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/HermesTimerContext.java +++ b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/HermesTimerContext.java @@ -10,19 +10,17 @@ public class HermesTimerContext implements Closeable { private final Timer micrometerTimer; - private final com.codahale.metrics.Timer graphiteTimer; private final Clock clock; private final long startNanos; - private HermesTimerContext(Timer micrometerTimer, com.codahale.metrics.Timer graphiteTimer, Clock clock) { + private HermesTimerContext(Timer micrometerTimer, Clock clock) { this.micrometerTimer = micrometerTimer; - this.graphiteTimer = graphiteTimer; this.clock = clock; this.startNanos = clock.monotonicTime(); } - public static HermesTimerContext from(Timer micrometerTimer, com.codahale.metrics.Timer graphiteTimer) { - return new HermesTimerContext(micrometerTimer, graphiteTimer, Clock.SYSTEM); + public static HermesTimerContext from(Timer micrometerTimer) { + return new HermesTimerContext(micrometerTimer, Clock.SYSTEM); } @Override @@ -36,7 +34,6 @@ public Duration closeAndGet() { private long reportTimer() { long amount = clock.monotonicTime() - startNanos; - graphiteTimer.update(amount, TimeUnit.NANOSECONDS); micrometerTimer.record(amount, TimeUnit.NANOSECONDS); return amount; } diff --git a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/PathContext.java b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/PathContext.java index 642b4edb3e..d96b017d9a 100644 --- a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/PathContext.java +++ b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/PathContext.java @@ -7,37 +7,13 @@ public class PathContext { private final Optional group; private final Optional topic; private final Optional subscription; - private final Optional kafkaTopic; - private final Optional partition; - private final Optional kafkaCluster; - private final Optional httpCode; - private final Optional httpCodeFamily; - private final Optional executorName; - private final Optional oAuthProviderName; - private final Optional schemaRepoType; private PathContext(Optional group, Optional topic, - Optional subscription, - Optional kafkaTopic, - Optional partition, - Optional kafkaCluster, - Optional httpCode, - Optional httpCodeFamily, - Optional executorName, - Optional oAuthProviderName, - Optional schemaRepoType) { + Optional subscription) { this.group = group; this.topic = topic; this.subscription = subscription; - this.kafkaTopic = kafkaTopic; - this.partition = partition; - this.kafkaCluster = kafkaCluster; - this.httpCode = httpCode; - this.httpCodeFamily = httpCodeFamily; - this.executorName = executorName; - this.oAuthProviderName = oAuthProviderName; - this.schemaRepoType = schemaRepoType; } public Optional getGroup() { @@ -52,37 +28,6 @@ public Optional getSubscription() { return subscription; } - public Optional getKafkaTopic() { - return kafkaTopic; - } - - public Optional getPartition() { - return partition; - } - - public Optional getKafkaCluster() { - return kafkaCluster; - } - - public Optional getHttpCode() { - return httpCode; - } - - public Optional getHttpCodeFamily() { - return httpCodeFamily; - } - - public Optional getExecutorName() { - return executorName; - } - - public Optional getoAuthProviderName() { - return oAuthProviderName; - } - - public Optional getSchemaRepoType() { - return schemaRepoType; - } public static Builder pathContext() { return new Builder(); @@ -93,14 +38,6 @@ public static class Builder { private Optional group = Optional.empty(); private Optional topic = Optional.empty(); private Optional subscription = Optional.empty(); - private Optional kafkaTopic = Optional.empty(); - private Optional partition = Optional.empty(); - private Optional kafkaCluster = Optional.empty(); - private Optional httpCode = Optional.empty(); - private Optional httpCodeFamily = Optional.empty(); - private Optional executorName = Optional.empty(); - private Optional oAuthProviderName = Optional.empty(); - private Optional schemaRepoType = Optional.empty(); public Builder withGroup(String group) { this.group = Optional.of(group); @@ -117,49 +54,8 @@ public Builder withSubscription(String subscription) { return this; } - public Builder withKafkaTopic(String kafkaTopic) { - this.kafkaTopic = Optional.of(kafkaTopic); - return this; - } - - public Builder withPartition(int partition) { - this.partition = Optional.of(partition); - return this; - } - - public Builder withKafkaCluster(String kafkaCluster) { - this.kafkaCluster = Optional.of(kafkaCluster); - return this; - } - - public Builder withHttpCode(int httpCode) { - this.httpCode = Optional.of(httpCode); - return this; - } - - public Builder withHttpCodeFamily(String httpCodeFamily) { - this.httpCodeFamily = Optional.of(httpCodeFamily); - return this; - } - - public Builder withExecutorName(String executorName) { - this.executorName = Optional.of(executorName); - return this; - } - - public Builder withOAuthProvider(String oAuthProviderName) { - this.oAuthProviderName = Optional.of(oAuthProviderName); - return this; - } - - public Builder withSchemaRepoType(String schemaRepoType) { - this.schemaRepoType = Optional.of(schemaRepoType); - return this; - } - public PathContext build() { - return new PathContext(group, topic, subscription, kafkaTopic, partition, kafkaCluster, - httpCode, httpCodeFamily, executorName, oAuthProviderName, schemaRepoType); + return new PathContext(group, topic, subscription); } } } diff --git a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/PathsCompiler.java b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/PathsCompiler.java index b517f4dbeb..c69e333740 100644 --- a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/PathsCompiler.java +++ b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/PathsCompiler.java @@ -1,6 +1,7 @@ package pl.allegro.tech.hermes.metrics; -import org.apache.commons.lang.text.StrBuilder; + +import org.apache.commons.text.TextStringBuilder; public class PathsCompiler { @@ -10,14 +11,6 @@ public class PathsCompiler { public static final String GROUP = "$group"; public static final String TOPIC = "$topic"; public static final String SUBSCRIPTION = "$subscription"; - public static final String KAFKA_TOPIC = "$kafka_topic"; - public static final String PARTITION = "$partition"; - public static final String KAFKA_CLUSTER = "$kafka_cluster"; - public static final String HTTP_CODE = "$http_code"; - public static final String HTTP_CODE_FAMILY = "$http_family_of_code"; - public static final String EXECUTOR_NAME = "$executor_name"; - public static final String OAUTH_PROVIDER_NAME = "$oauth_provider_name"; - public static final String SCHEMA_REPO_TYPE = "$schema_repo_type"; private final String hostname; @@ -30,19 +23,11 @@ public String compile(String path) { } public String compile(String path, PathContext context) { - StrBuilder pathBuilder = new StrBuilder(path); + TextStringBuilder pathBuilder = new TextStringBuilder(path); context.getGroup().ifPresent(g -> pathBuilder.replaceAll(GROUP, g)); context.getTopic().ifPresent(t -> pathBuilder.replaceAll(TOPIC, t)); context.getSubscription().ifPresent(s -> pathBuilder.replaceAll(SUBSCRIPTION, s)); - context.getKafkaTopic().ifPresent(k -> pathBuilder.replaceAll(KAFKA_TOPIC, k)); - context.getPartition().ifPresent(p -> pathBuilder.replaceAll(PARTITION, p.toString())); - context.getKafkaCluster().ifPresent(c -> pathBuilder.replaceAll(KAFKA_CLUSTER, c)); - context.getHttpCode().ifPresent(c -> pathBuilder.replaceAll(HTTP_CODE, c.toString())); - context.getHttpCodeFamily().ifPresent(cf -> pathBuilder.replaceAll(HTTP_CODE_FAMILY, cf)); - context.getExecutorName().ifPresent(c -> pathBuilder.replaceAll(EXECUTOR_NAME, c)); - context.getoAuthProviderName().ifPresent(c -> pathBuilder.replaceAll(OAUTH_PROVIDER_NAME, c)); - context.getSchemaRepoType().ifPresent(c -> pathBuilder.replaceAll(SCHEMA_REPO_TYPE, c)); pathBuilder.replaceAll(HOSTNAME, hostname); diff --git a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/counters/DefaultHermesCounter.java b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/counters/DefaultHermesCounter.java index cc9a4f69c5..c87629c534 100644 --- a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/counters/DefaultHermesCounter.java +++ b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/counters/DefaultHermesCounter.java @@ -5,16 +5,12 @@ public class DefaultHermesCounter implements HermesCounter { protected final io.micrometer.core.instrument.Counter micrometerCounter; - protected final com.codahale.metrics.Counter graphiteCounter; - protected DefaultHermesCounter(io.micrometer.core.instrument.Counter micrometerCounter, - com.codahale.metrics.Counter graphiteCounter) { + protected DefaultHermesCounter(io.micrometer.core.instrument.Counter micrometerCounter) { this.micrometerCounter = micrometerCounter; - this.graphiteCounter = graphiteCounter; } public void increment(long size) { this.micrometerCounter.increment((double) size); - this.graphiteCounter.inc(size); } } diff --git a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/counters/HermesCounters.java b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/counters/HermesCounters.java index c9329ca431..67b4e2f054 100644 --- a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/counters/HermesCounters.java +++ b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/counters/HermesCounters.java @@ -2,13 +2,7 @@ public class HermesCounters { - public static DefaultHermesCounter from(io.micrometer.core.instrument.Counter micrometerCounter, - com.codahale.metrics.Counter graphiteCounter) { - return new DefaultHermesCounter(micrometerCounter, graphiteCounter); - } - - public static MeterBackedHermesCounter from(io.micrometer.core.instrument.Counter micrometerCounter, - com.codahale.metrics.Meter graphiteMeter) { - return new MeterBackedHermesCounter(micrometerCounter, graphiteMeter); + public static DefaultHermesCounter from(io.micrometer.core.instrument.Counter micrometerCounter) { + return new DefaultHermesCounter(micrometerCounter); } } diff --git a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/counters/MeterBackedHermesCounter.java b/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/counters/MeterBackedHermesCounter.java deleted file mode 100644 index be226355eb..0000000000 --- a/hermes-metrics/src/main/java/pl/allegro/tech/hermes/metrics/counters/MeterBackedHermesCounter.java +++ /dev/null @@ -1,26 +0,0 @@ -package pl.allegro.tech.hermes.metrics.counters; - - -import pl.allegro.tech.hermes.metrics.HermesCounter; -import pl.allegro.tech.hermes.metrics.HermesRateMeter; - -public class MeterBackedHermesCounter implements HermesCounter, HermesRateMeter { - protected final io.micrometer.core.instrument.Counter micrometerCounter; - protected final com.codahale.metrics.Meter graphiteMeter; - - protected MeterBackedHermesCounter(io.micrometer.core.instrument.Counter micrometerCounter, - com.codahale.metrics.Meter graphiteMeter) { - this.micrometerCounter = micrometerCounter; - this.graphiteMeter = graphiteMeter; - } - - public void increment(long size) { - this.micrometerCounter.increment((double) size); - this.graphiteMeter.mark(size); - } - - @Override - public double getOneMinuteRate() { - return graphiteMeter.getOneMinuteRate(); - } -} diff --git a/hermes-metrics/src/test/groovy/pl.allegro.tech.hermes.metrics/PathsCompilerTest.groovy b/hermes-metrics/src/test/groovy/pl.allegro.tech.hermes.metrics/PathsCompilerTest.groovy index 5319ec8b4c..f37d9425cc 100644 --- a/hermes-metrics/src/test/groovy/pl.allegro.tech.hermes.metrics/PathsCompilerTest.groovy +++ b/hermes-metrics/src/test/groovy/pl.allegro.tech.hermes.metrics/PathsCompilerTest.groovy @@ -21,14 +21,12 @@ class PathsCompilerTest extends Specification { def pathContext = pathContext().withGroup("group") .withTopic("topic") .withSubscription("subscription") - .withPartition(0) - .withHttpCode(201) .build() when: - def compiled = pathsCompiler.compile("hermes.$GROUP.$TOPIC.$SUBSCRIPTION.$PARTITION.$HTTP_CODE", pathContext) + def compiled = pathsCompiler.compile("hermes.$GROUP.$TOPIC.$SUBSCRIPTION", pathContext) then: - compiled == "hermes.group.topic.subscription.0.201" + compiled == "hermes.group.topic.subscription" } } diff --git a/hermes-mock/build.gradle b/hermes-mock/build.gradle index e49c6a112b..f0cd9e2906 100644 --- a/hermes-mock/build.gradle +++ b/hermes-mock/build.gradle @@ -5,9 +5,9 @@ plugins { } dependencies { - implementation group: 'junit', name: 'junit', version: '4.11' + implementation group: 'junit', name: 'junit', version: '4.13.2' api group: 'org.wiremock', name: 'wiremock-standalone', version: versions.wiremock - implementation group: 'com.jayway.awaitility', name: 'awaitility', version: '1.6.1' + implementation group: 'org.awaitility', name: 'awaitility', version: '4.2.1' api group: 'org.apache.avro', name: 'avro', version: versions.avro implementation group: 'tech.allegro.schema.json2avro', name: 'converter', version: versions.json2avro implementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: versions.junit_jupiter @@ -18,9 +18,9 @@ dependencies { testImplementation group: 'org.apache.groovy', name: 'groovy-json', version: versions.groovy testImplementation group: 'org.glassfish.jersey.core', name: 'jersey-client', version: versions.jersey testImplementation group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: versions.jersey - testImplementation group: 'org.junit.jupiter', name :'junit-jupiter', version: versions.junit_jupiter + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: versions.junit_jupiter testImplementation group: 'org.springframework', name: 'spring-test', version: versions.spring_web - testRuntimeOnly group: 'org.junit.vintage', name : 'junit-vintage-engine', version: versions.junit_jupiter + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: versions.junit_jupiter } test { diff --git a/hermes-mock/src/main/java/pl/allegro/tech/hermes/mock/HermesMockExpect.java b/hermes-mock/src/main/java/pl/allegro/tech/hermes/mock/HermesMockExpect.java index 1872ad4364..7f503235a3 100644 --- a/hermes-mock/src/main/java/pl/allegro/tech/hermes/mock/HermesMockExpect.java +++ b/hermes-mock/src/main/java/pl/allegro/tech/hermes/mock/HermesMockExpect.java @@ -1,15 +1,15 @@ package pl.allegro.tech.hermes.mock; -import com.jayway.awaitility.core.ConditionTimeoutException; import org.apache.avro.Schema; +import org.awaitility.core.ConditionTimeoutException; import java.util.List; import java.util.function.Predicate; import java.util.function.Supplier; -import static com.jayway.awaitility.Awaitility.await; import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.stream.Collectors.toList; +import static org.awaitility.Awaitility.await; public class HermesMockExpect { private final HermesMockHelper hermesMockHelper; @@ -64,7 +64,7 @@ private void assertMessages(int count, Supplier> messages) { private void expectMessages(String topicName, int count) { try { - await().atMost(awaitSeconds, SECONDS).until(() -> hermesMockHelper.verifyRequest(count, topicName)); + await().atMost(awaitSeconds, SECONDS).untilAsserted(() -> hermesMockHelper.verifyRequest(count, topicName)); } catch (ConditionTimeoutException ex) { throw new HermesMockException("Hermes mock did not receive " + count + " messages.", ex); } diff --git a/hermes-test-helper/build.gradle b/hermes-test-helper/build.gradle index f02b8c2241..b24683e815 100644 --- a/hermes-test-helper/build.gradle +++ b/hermes-test-helper/build.gradle @@ -10,7 +10,7 @@ dependencies { implementation group: 'org.glassfish.jersey.core', name: 'jersey-client', version: versions.jersey implementation group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: versions.jersey implementation group: 'org.glassfish.jersey.ext', name: 'jersey-proxy-client', version: versions.jersey - api group: 'commons-io', name: 'commons-io', version: '2.4' + api group: 'commons-io', name: 'commons-io', version: '2.16.1' api group: 'org.wiremock', name: 'wiremock-standalone', version: versions.wiremock api (group: 'org.apache.curator', name: 'curator-test', version: versions.curator) { exclude module: 'slf4j-log4j12' @@ -24,14 +24,13 @@ dependencies { exclude module: 'slf4j-log4j12' exclude module: 'log4j' } - implementation group: 'com.google.code.findbugs', name: 'annotations', version: '3.0.0' - implementation group: 'com.jayway.awaitility', name: 'awaitility', version: '1.6.1' + implementation group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: '4.8.4' + implementation group: 'org.awaitility', name: 'awaitility-groovy', version: '4.2.1' implementation group: 'org.assertj', name: 'assertj-core', version: versions.assertj - api group: 'net.javacrumbs.json-unit', name: 'json-unit-fluent', version: '1.5.5' - implementation group: 'junit', name: 'junit', version: '4.11' - api group: 'org.testng', name: 'testng', version: '7.4.0' - implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.13' - implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.5.0' + api group: 'net.javacrumbs.json-unit', name: 'json-unit-fluent', version: '3.2.7' + implementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.10.2' + implementation group: 'org.apache.httpcomponents.client5', name: 'httpclient5', version: '5.3.1' + implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.9.0' implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: versions.jackson implementation group: 'org.springframework', name: 'spring-test', version: versions.spring_web implementation group: 'org.springframework', name: 'spring-webflux', version: versions.spring_web diff --git a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/builder/SubscriptionBuilder.java b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/builder/SubscriptionBuilder.java index 81b8012f30..63a4ecedff 100644 --- a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/builder/SubscriptionBuilder.java +++ b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/builder/SubscriptionBuilder.java @@ -50,6 +50,10 @@ public class SubscriptionBuilder { private boolean http2Enabled = false; + private boolean profilingEnabled = false; + + private long profilingThresholdMs = 0; + private OwnerId owner = new OwnerId("Plaintext", "some team"); private MonitoringDetails monitoringDetails = MonitoringDetails.EMPTY; @@ -126,8 +130,8 @@ public Subscription build() { topicName, name, endpoint, state, description, serialSubscriptionPolicy, trackingEnabled, trackingMode, owner, monitoringDetails, contentType, - filters, mode, headers, metadata, oAuthPolicy, http2Enabled, - attachingIdentityHeadersEnabled, autoDeleteWithTopicEnabled + filters, mode, headers, metadata, oAuthPolicy, http2Enabled, profilingEnabled, + profilingThresholdMs, attachingIdentityHeadersEnabled, autoDeleteWithTopicEnabled ); } else { return Subscription.createBatchSubscription( @@ -196,6 +200,16 @@ public SubscriptionBuilder withHttp2Enabled(boolean http2Enabled) { return this; } + public SubscriptionBuilder withProfilingEnabled(boolean profilingEnabled) { + this.profilingEnabled = profilingEnabled; + return this; + } + + public SubscriptionBuilder withProfilingThresholdMs(long profilingThresholdMs) { + this.profilingThresholdMs = profilingThresholdMs; + return this; + } + public SubscriptionBuilder withOwner(OwnerId owner) { this.owner = owner; return this; diff --git a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/client/integration/FrontendTestClient.java b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/client/integration/FrontendTestClient.java index 86964105e9..bb29c99df1 100644 --- a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/client/integration/FrontendTestClient.java +++ b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/client/integration/FrontendTestClient.java @@ -40,6 +40,9 @@ public FrontendTestClient(int frontendPort) { this.webTestClient = WebTestClient .bindToServer(new JdkClientHttpConnector()) .baseUrl(frontendContainerUrl) + .codecs(configurer -> configurer + .defaultCodecs() + .maxInMemorySize(16 * 1024 * 1024)) .build(); this.slowTestClient = new FrontendSlowClient("localhost", frontendPort); this.chunkedClient = newClient(new ClientConfig().property(REQUEST_ENTITY_PROCESSING, CHUNKED)); diff --git a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/client/integration/HermesInitHelper.java b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/client/integration/HermesInitHelper.java index fb47861480..d90c793d07 100644 --- a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/client/integration/HermesInitHelper.java +++ b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/client/integration/HermesInitHelper.java @@ -1,14 +1,14 @@ package pl.allegro.tech.hermes.test.helper.client.integration; -import com.jayway.awaitility.Duration; +import java.time.Duration; import pl.allegro.tech.hermes.api.Group; import pl.allegro.tech.hermes.api.OAuthProvider; import pl.allegro.tech.hermes.api.Subscription; import pl.allegro.tech.hermes.api.Topic; import pl.allegro.tech.hermes.api.TopicWithSchema; -import static com.jayway.awaitility.Awaitility.waitAtMost; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; public class HermesInitHelper { @@ -61,13 +61,13 @@ public Group createGroup(Group group) { } private void waitUntilGroupCreated(String groupName) { - waitAtMost(Duration.ONE_MINUTE) + waitAtMost(Duration.ofMinutes(1)) .until(() -> managementTestClient.getGroups().contains(groupName)); } private void waitUntilTopicCreated(String topicQualifiedName) { - waitAtMost(Duration.ONE_MINUTE) - .until(() -> managementTestClient.getTopic(topicQualifiedName) + waitAtMost(Duration.ofMinutes(1)) + .untilAsserted(() -> managementTestClient.getTopic(topicQualifiedName) .expectStatus() .is2xxSuccessful()); } @@ -81,8 +81,8 @@ public Subscription createSubscription(Subscription subscription) { } public void waitUntilSubscriptionIsActive(Subscription subscription) { - waitAtMost(Duration.TEN_SECONDS) - .until(() -> { + waitAtMost(Duration.ofSeconds(10)) + .untilAsserted(() -> { Subscription sub = managementTestClient.getSubscription(subscription.getQualifiedTopicName(), subscription.getName()) .expectStatus() .is2xxSuccessful() diff --git a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/client/integration/HermesTestClient.java b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/client/integration/HermesTestClient.java index 43c183f27a..7ac2fcd6df 100644 --- a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/client/integration/HermesTestClient.java +++ b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/client/integration/HermesTestClient.java @@ -1,7 +1,8 @@ package pl.allegro.tech.hermes.test.helper.client.integration; -import com.jayway.awaitility.Duration; import jakarta.ws.rs.core.Response; +import java.time.Duration; +import org.assertj.core.api.Assertions; import org.springframework.http.HttpHeaders; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.util.MultiValueMap; @@ -21,7 +22,8 @@ import java.io.IOException; import java.util.List; -import static com.jayway.awaitility.Awaitility.waitAtMost; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.test.helper.endpoint.TimeoutAdjuster.adjust; public class HermesTestClient { @@ -61,7 +63,7 @@ public WebTestClient.ResponseSpec saveSchema(String topicQualifiedName, String s public void ensureSchemaSaved(String topicQualifiedName, boolean validate, String schema) { managementTestClient.saveSchema(topicQualifiedName, validate, schema) .expectStatus().isCreated(); - waitAtMost(adjust(Duration.ONE_MINUTE)).until(() -> + waitAtMost(adjust(Duration.ofMinutes(1))).untilAsserted(() -> managementTestClient.getSchema(topicQualifiedName).expectStatus().isOk() ); } @@ -106,33 +108,37 @@ public WebTestClient.ResponseSpec suspendSubscription(Topic topic, String subscr } public void waitUntilSubscriptionActivated(String topicQualifiedName, String subscriptionName) { - waitAtMost(Duration.TEN_SECONDS) - .until(() -> { - managementTestClient.getSubscription(topicQualifiedName, subscriptionName) + waitAtMost(Duration.ofSeconds(10)) + .untilAsserted(() -> { + assertThat(managementTestClient.getSubscription(topicQualifiedName, subscriptionName) .expectStatus() .is2xxSuccessful() .expectBody(Subscription.class) - .returnResult().getResponseBody().getState().equals(Subscription.State.ACTIVE); - managementTestClient.getConsumerGroupsDescription(topicQualifiedName, subscriptionName).expectBodyList(ConsumerGroup.class).returnResult().getResponseBody() + .returnResult().getResponseBody().getState()) + .isEqualTo(Subscription.State.ACTIVE); + assertThat(managementTestClient.getConsumerGroupsDescription(topicQualifiedName, subscriptionName) + .expectBodyList(ConsumerGroup.class).returnResult().getResponseBody() .get(0) - .getState() - .equals("Stable"); + .getState()) + .isEqualTo("Stable"); } ); } public void waitUntilSubscriptionSuspended(String topicQualifiedName, String subscriptionName) { - waitAtMost(Duration.TEN_SECONDS) - .until(() -> { - managementTestClient.getSubscription(topicQualifiedName, subscriptionName) + waitAtMost(Duration.ofSeconds(10)) + .untilAsserted(() -> { + assertThat(managementTestClient.getSubscription(topicQualifiedName, subscriptionName) .expectStatus() .is2xxSuccessful() .expectBody(Subscription.class) - .returnResult().getResponseBody().getState().equals(Subscription.State.SUSPENDED); - managementTestClient.getConsumerGroupsDescription(topicQualifiedName, subscriptionName).expectBodyList(ConsumerGroup.class).returnResult().getResponseBody() + .returnResult().getResponseBody().getState()) + .isEqualTo(Subscription.State.SUSPENDED); + assertThat(managementTestClient.getConsumerGroupsDescription(topicQualifiedName, subscriptionName) + .expectBodyList(ConsumerGroup.class).returnResult().getResponseBody() .get(0) - .getState() - .equals("Empty"); + .getState()) + .isEqualTo("Empty"); } ); } diff --git a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/containers/ImageTags.java b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/containers/ImageTags.java index d140544320..3c2751bc42 100644 --- a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/containers/ImageTags.java +++ b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/containers/ImageTags.java @@ -2,6 +2,9 @@ public class ImageTags { public static String confluentImagesTag() { + if (System.getProperty("os.arch").equals("aarch64")) { + return System.getProperty("confluentImagesTag", "7.6.1"); + } return System.getProperty("confluentImagesTag", "6.1.0"); } } diff --git a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/endpoint/RemoteServiceEndpoint.java b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/endpoint/RemoteServiceEndpoint.java index da4c479bc6..64adf9918a 100644 --- a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/endpoint/RemoteServiceEndpoint.java +++ b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/endpoint/RemoteServiceEndpoint.java @@ -4,7 +4,7 @@ import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.verification.LoggedRequest; import com.google.common.collect.Iterables; -import com.jayway.awaitility.Duration; +import java.time.Duration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pl.allegro.tech.hermes.test.helper.message.TestMessage; @@ -22,10 +22,10 @@ import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED; -import static com.jayway.awaitility.Awaitility.await; import static java.util.stream.Collectors.toList; import static jakarta.ws.rs.core.Response.Status.MOVED_PERMANENTLY; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import static pl.allegro.tech.hermes.test.helper.endpoint.TimeoutAdjuster.adjust; public class RemoteServiceEndpoint { @@ -77,9 +77,9 @@ public void expectMessages(List messages) { receivedRequests.clear(); expectedMessages = messages; messages.forEach(m -> listener - .register( - post(urlEqualTo(path)) - .willReturn(aResponse().withStatus(returnedStatusCode).withFixedDelay(delay)))); + .register( + post(urlEqualTo(path)) + .willReturn(aResponse().withStatus(returnedStatusCode).withFixedDelay(delay)))); } public void redirectMessage(String message) { @@ -88,10 +88,10 @@ public void redirectMessage(String message) { expectedMessages = Collections.singletonList(message); listener.register( - post(urlEqualTo(path)) - .willReturn(aResponse() - .withStatus(MOVED_PERMANENTLY.getStatusCode()) - .withHeader("Location", "http://localhost:" + service.port()))); + post(urlEqualTo(path)) + .willReturn(aResponse() + .withStatus(MOVED_PERMANENTLY.getStatusCode()) + .withHeader("Location", "http://localhost:" + service.port()))); } public void retryMessage(String message, int delay) { @@ -149,7 +149,7 @@ public void setReturnedStatusCode(int statusCode) { public void waitUntilReceived(long seconds) { logger.info("Expecting to receive {} messages", expectedMessages.size()); - await().atMost(adjust(new Duration(seconds, TimeUnit.SECONDS))).until(() -> + await().atMost(adjust(Duration.ofSeconds(seconds))).untilAsserted(() -> assertThat(receivedRequests.size()).isGreaterThanOrEqualTo(expectedMessages.size())); synchronized (receivedRequests) { assertThat(receivedRequests.stream().map(LoggedRequest::getBodyAsString).collect(toList())).containsAll(expectedMessages); @@ -157,7 +157,8 @@ public void waitUntilReceived(long seconds) { } public void waitUntilReceived(long seconds, int numberOfExpectedMessages) { - waitUntilReceived(seconds, numberOfExpectedMessages, body -> {}); + waitUntilReceived(seconds, numberOfExpectedMessages, body -> { + }); } public void waitUntilReceived(Consumer requestBodyConsumer) { @@ -170,7 +171,7 @@ public void waitUntilRequestReceived(Consumer requestConsumer) { public void waitUntilReceived(long seconds, int numberOfExpectedMessages, Consumer requestBodyConsumer) { logger.info("Expecting to receive {} messages", numberOfExpectedMessages); - await().atMost(adjust(new Duration(seconds, TimeUnit.SECONDS))).until(() -> + await().atMost(adjust(Duration.ofSeconds(seconds))).untilAsserted(() -> assertThat(receivedRequests.size()).isGreaterThanOrEqualTo(numberOfExpectedMessages)); synchronized (receivedRequests) { receivedRequests.forEach(requestBodyConsumer); @@ -179,7 +180,7 @@ public void waitUntilReceived(long seconds, int numberOfExpectedMessages, Consum public void waitUntilReceived(Duration duration, int numberOfExpectedMessages, Consumer requestBodyConsumer) { logger.info("Expecting to receive {} messages", numberOfExpectedMessages); - await().atMost(duration).until(() -> assertThat(receivedRequests.size()).isEqualTo(numberOfExpectedMessages)); + await().atMost(duration).untilAsserted(() -> assertThat(receivedRequests.size()).isEqualTo(numberOfExpectedMessages)); synchronized (receivedRequests) { receivedRequests.forEach(requestBodyConsumer); } diff --git a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/endpoint/TimeoutAdjuster.java b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/endpoint/TimeoutAdjuster.java index 3a94138ee9..2d06f09c44 100644 --- a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/endpoint/TimeoutAdjuster.java +++ b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/endpoint/TimeoutAdjuster.java @@ -1,8 +1,6 @@ package pl.allegro.tech.hermes.test.helper.endpoint; -import com.jayway.awaitility.Duration; - -import java.util.concurrent.TimeUnit; +import java.time.Duration; import static java.lang.Double.parseDouble; @@ -14,6 +12,6 @@ public static long adjust(long value) { } public static Duration adjust(Duration duration) { - return new Duration(adjust(duration.getValueInMS()), TimeUnit.MILLISECONDS); + return Duration.ofMillis(adjust(duration.toMillis())); } } diff --git a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/metrics/TestMetricsFacadeFactory.java b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/metrics/TestMetricsFacadeFactory.java index 1b415b44a9..8037c05db3 100644 --- a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/metrics/TestMetricsFacadeFactory.java +++ b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/metrics/TestMetricsFacadeFactory.java @@ -1,17 +1,11 @@ package pl.allegro.tech.hermes.test.helper.metrics; -import com.codahale.metrics.MetricRegistry; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; -import pl.allegro.tech.hermes.metrics.PathsCompiler; public class TestMetricsFacadeFactory { public static MetricsFacade create() { - return new MetricsFacade( - new SimpleMeterRegistry(), - new HermesMetrics(new MetricRegistry(), new PathsCompiler("localhost")) - ); + return new MetricsFacade(new SimpleMeterRegistry()); } } diff --git a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/oauth/server/OAuthTestServer.java b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/oauth/server/OAuthTestServer.java index e7fdfafaa6..acb3b9e767 100644 --- a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/oauth/server/OAuthTestServer.java +++ b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/oauth/server/OAuthTestServer.java @@ -11,7 +11,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; -import static org.apache.http.HttpStatus.SC_OK; +import static org.apache.hc.core5.http.HttpStatus.SC_OK; public class OAuthTestServer { diff --git a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/retry/Retry.java b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/retry/Retry.java deleted file mode 100644 index b0411a4235..0000000000 --- a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/retry/Retry.java +++ /dev/null @@ -1,28 +0,0 @@ -package pl.allegro.tech.hermes.test.helper.retry; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.IRetryAnalyzer; -import org.testng.ITestResult; - -import static java.lang.Integer.parseInt; - -public class Retry implements IRetryAnalyzer { - private int retryCount = 0; - private static final int maxRetryCount = parseInt(System.getProperty("tests.retry.count", "2")); - private static final Logger logger = LoggerFactory.getLogger(Retry.class); - - @Override - public boolean retry(ITestResult result) { - logger.error("Retrying test {}.{}", result.getTestClass().getName(), result.getMethod().getMethodName(), result.getThrowable()); - if (isRetryAvailable()) { - retryCount++; - return true; - } - return false; - } - - public boolean isRetryAvailable() { - return retryCount < maxRetryCount; - } -} diff --git a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/retry/RetryListener.java b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/retry/RetryListener.java deleted file mode 100644 index 7049dab36c..0000000000 --- a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/retry/RetryListener.java +++ /dev/null @@ -1,18 +0,0 @@ -package pl.allegro.tech.hermes.test.helper.retry; - -import org.testng.IRetryAnalyzer; -import org.testng.ITestResult; -import org.testng.Reporter; -import org.testng.TestListenerAdapter; - -public class RetryListener extends TestListenerAdapter { - - @Override - public void onTestFailure(ITestResult result) { - IRetryAnalyzer analyzer = result.getMethod().getRetryAnalyzer(result); - if (analyzer instanceof Retry) { - result.setStatus(((Retry) analyzer).isRetryAvailable() ? ITestResult.SKIP : ITestResult.FAILURE); - Reporter.setCurrentTestResult(result); - } - } -} diff --git a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/zookeeper/ZookeeperWaiter.java b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/zookeeper/ZookeeperWaiter.java index 937caffeaa..3e9fcb0bea 100644 --- a/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/zookeeper/ZookeeperWaiter.java +++ b/hermes-test-helper/src/main/java/pl/allegro/tech/hermes/test/helper/zookeeper/ZookeeperWaiter.java @@ -5,7 +5,8 @@ import java.util.concurrent.TimeUnit; -import static com.jayway.awaitility.Awaitility.await; +import static org.awaitility.Awaitility.await; + public class ZookeeperWaiter { diff --git a/hermes-tracker-elasticsearch/build.gradle b/hermes-tracker-elasticsearch/build.gradle index 9641184d82..6e18bada83 100644 --- a/hermes-tracker-elasticsearch/build.gradle +++ b/hermes-tracker-elasticsearch/build.gradle @@ -4,15 +4,16 @@ plugins { dependencies { implementation project(':hermes-common') implementation project(':hermes-tracker') - implementation 'org.slf4j:slf4j-api:2.0.4' + implementation 'org.slf4j:slf4j-api:2.0.13' + // TODO: client has to have the same major version as backend: https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/client.html + // we need to use test-containers for elasticsearch server to able to use newer client. api group: 'org.elasticsearch.client', name: 'transport', version: '6.8.12' testImplementation project(path: ":hermes-tracker", configuration: "testArtifacts") testImplementation project(path: ":hermes-test-helper") testImplementation group: 'org.spockframework', name: 'spock-core', version: versions.spock testImplementation group: 'org.spockframework', name: 'spock-junit4', version: versions.spock + // this should be migrated to testcontainers testImplementation 'pl.allegro.tech:embedded-elasticsearch:2.10.0' testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine', version: versions.junit_jupiter -} - -test.useTestNG() \ No newline at end of file +} \ No newline at end of file diff --git a/hermes-tracker-elasticsearch/src/main/java/pl/allegro/tech/hermes/tracker/elasticsearch/ElasticsearchQueueCommitter.java b/hermes-tracker-elasticsearch/src/main/java/pl/allegro/tech/hermes/tracker/elasticsearch/ElasticsearchQueueCommitter.java index daed417560..8e5e12d232 100644 --- a/hermes-tracker-elasticsearch/src/main/java/pl/allegro/tech/hermes/tracker/elasticsearch/ElasticsearchQueueCommitter.java +++ b/hermes-tracker-elasticsearch/src/main/java/pl/allegro/tech/hermes/tracker/elasticsearch/ElasticsearchQueueCommitter.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.tracker.elasticsearch; -import com.codahale.metrics.Timer; import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.elasticsearch.action.bulk.BulkRequestBuilder; import org.elasticsearch.client.Client; diff --git a/hermes-tracker-elasticsearch/src/main/java/pl/allegro/tech/hermes/tracker/elasticsearch/management/MultiElasticsearchLogRepository.java b/hermes-tracker-elasticsearch/src/main/java/pl/allegro/tech/hermes/tracker/elasticsearch/management/MultiElasticsearchLogRepository.java index b49e5d0afc..d5aaf7a0ef 100644 --- a/hermes-tracker-elasticsearch/src/main/java/pl/allegro/tech/hermes/tracker/elasticsearch/management/MultiElasticsearchLogRepository.java +++ b/hermes-tracker-elasticsearch/src/main/java/pl/allegro/tech/hermes/tracker/elasticsearch/management/MultiElasticsearchLogRepository.java @@ -12,7 +12,7 @@ public class MultiElasticsearchLogRepository implements LogRepository, LogSchemaAware { - private List elasticsearchLogRepositories; + private final List elasticsearchLogRepositories; public MultiElasticsearchLogRepository(List elasticClients) { elasticsearchLogRepositories = elasticClients.stream() diff --git a/hermes-tracker-elasticsearch/src/test/groovy/pl/allegro/tech/hermes/tracker/elasticsearch/DailyIndexFactoryTest.groovy b/hermes-tracker-elasticsearch/src/test/groovy/pl/allegro/tech/hermes/tracker/elasticsearch/DailyIndexFactoryTest.groovy index bd4d0adcd1..c76f236fbe 100644 --- a/hermes-tracker-elasticsearch/src/test/groovy/pl/allegro/tech/hermes/tracker/elasticsearch/DailyIndexFactoryTest.groovy +++ b/hermes-tracker-elasticsearch/src/test/groovy/pl/allegro/tech/hermes/tracker/elasticsearch/DailyIndexFactoryTest.groovy @@ -9,7 +9,6 @@ import java.time.Clock import static java.time.LocalDate.of import static java.time.ZoneId.systemDefault import static java.time.ZoneOffset.UTC -import static org.assertj.core.api.Assertions.assertThat class DailyIndexFactoryTest extends Specification { @@ -18,7 +17,7 @@ class DailyIndexFactoryTest extends Specification { def "should create daily index"() { expect: - assertThat(indexFactory.createIndex()).endsWith("_2000_01_01") + indexFactory.createIndex().endsWith("_2000_01_01") where: indexFactory << [new FrontendDailyIndexFactory(clock), new ConsumersDailyIndexFactory(clock)] diff --git a/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/consumers/ConsumersElasticsearchLogRepositoryTest.java b/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/consumers/ConsumersElasticsearchLogRepositoryTest.java index 3f4d5de1c0..20d0aa0e6d 100644 --- a/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/consumers/ConsumersElasticsearchLogRepositoryTest.java +++ b/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/consumers/ConsumersElasticsearchLogRepositoryTest.java @@ -1,16 +1,13 @@ package pl.allegro.tech.hermes.tracker.elasticsearch.consumers; -import com.codahale.metrics.MetricRegistry; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; -import org.testng.annotations.AfterSuite; -import org.testng.annotations.BeforeSuite; +import org.junit.AfterClass; +import org.junit.BeforeClass; import pl.allegro.tech.hermes.api.SentMessageTraceStatus; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; -import pl.allegro.tech.hermes.metrics.PathsCompiler; import pl.allegro.tech.hermes.tracker.consumers.AbstractLogRepositoryTest; import pl.allegro.tech.hermes.tracker.consumers.LogRepository; import pl.allegro.tech.hermes.tracker.elasticsearch.ElasticsearchResource; @@ -20,12 +17,12 @@ import pl.allegro.tech.hermes.tracker.elasticsearch.frontend.FrontendIndexFactory; import java.time.Clock; +import java.time.Duration; import java.time.LocalDate; import java.time.ZoneId; import java.time.ZoneOffset; -import static com.jayway.awaitility.Awaitility.await; -import static com.jayway.awaitility.Duration.ONE_MINUTE; +import static org.awaitility.Awaitility.await; import static org.elasticsearch.index.query.QueryBuilders.boolQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery; @@ -37,22 +34,21 @@ public class ConsumersElasticsearchLogRepositoryTest extends AbstractLogReposito private static final ConsumersIndexFactory indexFactory = new ConsumersDailyIndexFactory(clock); private static final FrontendIndexFactory frontendIndexFactory = new FrontendDailyIndexFactory(clock); private static final MetricsFacade metricsFacade = new MetricsFacade( - new SimpleMeterRegistry(), - new HermesMetrics(new MetricRegistry(), new PathsCompiler("")) + new SimpleMeterRegistry() ); - private static ElasticsearchResource elasticsearch = new ElasticsearchResource(); - private SchemaManager schemaManager; + private static final ElasticsearchResource elasticsearch = new ElasticsearchResource(); + private static SchemaManager schemaManager; - @BeforeSuite - public void before() throws Throwable { + @BeforeClass + public static void beforeAll() throws Throwable { elasticsearch.before(); schemaManager = new SchemaManager(elasticsearch.client(), frontendIndexFactory, indexFactory, false); } - @AfterSuite - public void after() { + @AfterClass + public static void afterAll() { elasticsearch.after(); } @@ -77,7 +73,7 @@ protected void awaitUntilBatchMessageIsPersisted(String topic, String subscripti } private void awaitUntilPersisted(QueryBuilder query) { - await().atMost(ONE_MINUTE).until(() -> { + await().atMost(Duration.ofMinutes(1)).until(() -> { SearchResponse response = elasticsearch.client().prepareSearch(indexFactory.createIndex()) .setTypes(SchemaManager.SENT_TYPE) .setQuery(query) diff --git a/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/frontend/FrontendElasticsearchLogRepositoryTest.java b/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/frontend/FrontendElasticsearchLogRepositoryTest.java index 05c2384763..329824b414 100644 --- a/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/frontend/FrontendElasticsearchLogRepositoryTest.java +++ b/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/frontend/FrontendElasticsearchLogRepositoryTest.java @@ -1,16 +1,13 @@ package pl.allegro.tech.hermes.tracker.elasticsearch.frontend; -import com.codahale.metrics.MetricRegistry; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; -import org.testng.annotations.AfterSuite; -import org.testng.annotations.BeforeSuite; +import org.junit.AfterClass; +import org.junit.BeforeClass; import pl.allegro.tech.hermes.api.PublishedMessageTraceStatus; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; -import pl.allegro.tech.hermes.metrics.PathsCompiler; import pl.allegro.tech.hermes.tracker.elasticsearch.ElasticsearchResource; import pl.allegro.tech.hermes.tracker.elasticsearch.LogSchemaAware; import pl.allegro.tech.hermes.tracker.elasticsearch.SchemaManager; @@ -20,12 +17,12 @@ import pl.allegro.tech.hermes.tracker.frontend.LogRepository; import java.time.Clock; +import java.time.Duration; import java.time.LocalDate; import java.time.ZoneId; import java.time.ZoneOffset; -import static com.jayway.awaitility.Awaitility.await; -import static com.jayway.awaitility.Duration.ONE_MINUTE; +import static org.awaitility.Awaitility.await; import static org.elasticsearch.index.query.QueryBuilders.boolQuery; import static org.elasticsearch.index.query.QueryBuilders.matchQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery; @@ -38,22 +35,21 @@ public class FrontendElasticsearchLogRepositoryTest extends AbstractLogRepositor private static final FrontendIndexFactory frontendIndexFactory = new FrontendDailyIndexFactory(clock); private static final ConsumersIndexFactory consumersIndexFactory = new ConsumersDailyIndexFactory(clock); private static final MetricsFacade metricsFacade = new MetricsFacade( - new SimpleMeterRegistry(), - new HermesMetrics(new MetricRegistry(), new PathsCompiler("")) + new SimpleMeterRegistry() ); private static final ElasticsearchResource elasticsearch = new ElasticsearchResource(); - private SchemaManager schemaManager; + private static SchemaManager schemaManager; - @BeforeSuite - public void before() throws Throwable { + @BeforeClass + public static void beforeAll() throws Throwable { elasticsearch.before(); schemaManager = new SchemaManager(elasticsearch.client(), frontendIndexFactory, consumersIndexFactory, false); } - @AfterSuite - public void after() { + @AfterClass + public static void afterAll() { elasticsearch.after(); } @@ -114,7 +110,7 @@ private BoolQueryBuilder getQuery(String topic, } private void awaitUntilMessageIsIndexed(QueryBuilder query) { - await().atMost(ONE_MINUTE).until(() -> { + await().atMost(Duration.ofMinutes(1)).until(() -> { SearchResponse response = elasticsearch.client().prepareSearch(frontendIndexFactory.createIndex()) .setTypes(SchemaManager.PUBLISHED_TYPE) .setQuery(query) diff --git a/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/management/ElasticsearchLogRepositoryTest.java b/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/management/ElasticsearchLogRepositoryTest.java index e3755e8a85..0f36d0a768 100644 --- a/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/management/ElasticsearchLogRepositoryTest.java +++ b/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/management/ElasticsearchLogRepositoryTest.java @@ -1,19 +1,18 @@ package pl.allegro.tech.hermes.tracker.elasticsearch.management; -import com.codahale.metrics.MetricRegistry; import com.google.common.collect.ImmutableMap; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; -import org.testng.annotations.AfterSuite; -import org.testng.annotations.BeforeSuite; -import org.testng.annotations.Test; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; import pl.allegro.tech.hermes.api.MessageTrace; import pl.allegro.tech.hermes.api.PublishedMessageTrace; import pl.allegro.tech.hermes.api.PublishedMessageTraceStatus; import pl.allegro.tech.hermes.api.SentMessageTrace; import pl.allegro.tech.hermes.api.SentMessageTraceStatus; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; -import pl.allegro.tech.hermes.metrics.PathsCompiler; import pl.allegro.tech.hermes.tracker.consumers.MessageMetadata; import pl.allegro.tech.hermes.tracker.consumers.TestMessageMetadata; import pl.allegro.tech.hermes.tracker.elasticsearch.ElasticsearchResource; @@ -28,6 +27,7 @@ import pl.allegro.tech.hermes.tracker.management.LogRepository; import java.time.Clock; +import java.time.Duration; import java.time.LocalDate; import java.time.ZoneId; import java.time.ZoneOffset; @@ -35,9 +35,8 @@ import java.util.List; import java.util.Map; -import static com.jayway.awaitility.Awaitility.await; -import static com.jayway.awaitility.Duration.ONE_MINUTE; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import static pl.allegro.tech.hermes.api.SentMessageTraceStatus.DISCARDED; import static pl.allegro.tech.hermes.common.http.ExtraRequestHeadersCollector.extraRequestHeadersCollector; @@ -50,8 +49,7 @@ public class ElasticsearchLogRepositoryTest implements LogSchemaAware { private static final FrontendIndexFactory frontendIndexFactory = new FrontendDailyIndexFactory(clock); private static final ConsumersIndexFactory consumersIndexFactory = new ConsumersDailyIndexFactory(clock); private static final MetricsFacade metricsFacade = new MetricsFacade( - new SimpleMeterRegistry(), - new HermesMetrics(new MetricRegistry(), new PathsCompiler("")) + new SimpleMeterRegistry() ); private static final ElasticsearchResource elasticsearch = new ElasticsearchResource(); @@ -60,9 +58,18 @@ public class ElasticsearchLogRepositoryTest implements LogSchemaAware { private FrontendElasticsearchLogRepository frontendLogRepository; private ConsumersElasticsearchLogRepository consumersLogRepository; - @BeforeSuite - public void before() throws Throwable { + @BeforeClass + public static void beforeAll() throws Throwable { elasticsearch.before(); + } + + @AfterClass + public static void afterAll() { + elasticsearch.after(); + } + + @Before + public void setUp() { SchemaManager schemaManager = new SchemaManager(elasticsearch.client(), frontendIndexFactory, consumersIndexFactory, false); logRepository = new ElasticsearchLogRepository(elasticsearch.client(), schemaManager); @@ -77,13 +84,9 @@ public void before() throws Throwable { .build(); } - @AfterSuite - public void after() { - elasticsearch.after(); - } - // TODO: figure out why this test sometimes *consistently* fails on CI - @Test(enabled = false) + @Ignore + @Test public void shouldGetLastUndelivered() throws Exception { //given String topic = "elasticsearch.lastUndelivered"; @@ -124,7 +127,7 @@ public void shouldGetMessageStatus() { private List fetchLastUndelivered(String topic, String subscription) { final List lastUndelivered = new ArrayList<>(); - await().atMost(ONE_MINUTE).until(() -> { + await().atMost(Duration.ofMinutes(1)).until(() -> { lastUndelivered.clear(); lastUndelivered.addAll(logRepository.getLastUndeliveredMessages(topic, subscription, 1)); return lastUndelivered.size() == 1; @@ -135,7 +138,7 @@ private List fetchLastUndelivered(String topic, String subscri private List fetchMessageStatus(MessageMetadata messageMetadata) { List status = new ArrayList<>(); - await().atMost(ONE_MINUTE).until(() -> { + await().atMost(Duration.ofMinutes(1)).until(() -> { status.clear(); status.addAll(logRepository.getMessageStatus(messageMetadata.getTopic(), messageMetadata.getSubscription(), messageMetadata.getMessageId())); diff --git a/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/management/MultiElasticsearchLogRepositoryTest.java b/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/management/MultiElasticsearchLogRepositoryTest.java index 877a2e499a..917dbf971c 100644 --- a/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/management/MultiElasticsearchLogRepositoryTest.java +++ b/hermes-tracker-elasticsearch/src/test/java/pl/allegro/tech/hermes/tracker/elasticsearch/management/MultiElasticsearchLogRepositoryTest.java @@ -1,24 +1,21 @@ package pl.allegro.tech.hermes.tracker.elasticsearch.management; -import com.codahale.metrics.MetricRegistry; import com.google.common.collect.ImmutableMap; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; -import org.testng.annotations.AfterSuite; -import org.testng.annotations.BeforeSuite; -import org.testng.annotations.Test; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; import pl.allegro.tech.hermes.api.MessageTrace; import pl.allegro.tech.hermes.api.PublishedMessageTrace; import pl.allegro.tech.hermes.api.PublishedMessageTraceStatus; import pl.allegro.tech.hermes.api.SentMessageTrace; import pl.allegro.tech.hermes.api.SentMessageTraceStatus; -import pl.allegro.tech.hermes.common.metric.HermesMetrics; import pl.allegro.tech.hermes.common.metric.MetricsFacade; -import pl.allegro.tech.hermes.metrics.PathsCompiler; import pl.allegro.tech.hermes.tracker.consumers.MessageMetadata; import pl.allegro.tech.hermes.tracker.consumers.TestMessageMetadata; import pl.allegro.tech.hermes.tracker.elasticsearch.ElasticsearchResource; import pl.allegro.tech.hermes.tracker.elasticsearch.LogSchemaAware; -import pl.allegro.tech.hermes.tracker.elasticsearch.SchemaManager; import pl.allegro.tech.hermes.tracker.elasticsearch.consumers.ConsumersDailyIndexFactory; import pl.allegro.tech.hermes.tracker.elasticsearch.consumers.ConsumersElasticsearchLogRepository; import pl.allegro.tech.hermes.tracker.elasticsearch.consumers.ConsumersIndexFactory; @@ -28,6 +25,7 @@ import pl.allegro.tech.hermes.tracker.management.LogRepository; import java.time.Clock; +import java.time.Duration; import java.time.LocalDate; import java.time.ZoneId; import java.time.ZoneOffset; @@ -36,9 +34,8 @@ import java.util.List; import java.util.Map; -import static com.jayway.awaitility.Awaitility.await; -import static com.jayway.awaitility.Duration.ONE_MINUTE; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import static pl.allegro.tech.hermes.common.http.ExtraRequestHeadersCollector.extraRequestHeadersCollector; @@ -51,8 +48,7 @@ public class MultiElasticsearchLogRepositoryTest implements LogSchemaAware { private static final FrontendIndexFactory frontendIndexFactory = new FrontendDailyIndexFactory(clock); private static final ConsumersIndexFactory consumersIndexFactory = new ConsumersDailyIndexFactory(clock); private static final MetricsFacade metricsFacade = new MetricsFacade( - new SimpleMeterRegistry(), - new HermesMetrics(new MetricRegistry(), new PathsCompiler("")) + new SimpleMeterRegistry() ); private static final ElasticsearchResource elasticsearch1 = new ElasticsearchResource(); @@ -62,12 +58,20 @@ public class MultiElasticsearchLogRepositoryTest implements LogSchemaAware { private FrontendElasticsearchLogRepository frontendLogRepository; private ConsumersElasticsearchLogRepository consumersLogRepository; - @BeforeSuite - public void before() throws Throwable { + @BeforeClass + public static void beforeAll() throws Throwable { elasticsearch1.before(); elasticsearch2.before(); + } + + @AfterClass + public static void afterAll() { + elasticsearch1.after(); + elasticsearch2.after(); + } - SchemaManager schemaManager = new SchemaManager(elasticsearch1.client(), frontendIndexFactory, consumersIndexFactory, false); + @Before + public void setUp() { logRepository = new MultiElasticsearchLogRepository(Arrays.asList(elasticsearch1.client(), elasticsearch2.client())); frontendLogRepository = new FrontendElasticsearchLogRepository.Builder( @@ -81,12 +85,6 @@ public void before() throws Throwable { .build(); } - @AfterSuite - public void after() { - elasticsearch1.after(); - elasticsearch2.after(); - } - @Test public void shouldGetMessageStatus() { // given @@ -108,7 +106,7 @@ public void shouldGetMessageStatus() { private List fetchMessageStatus(MessageMetadata messageMetadata) { List status = new ArrayList<>(); - await().atMost(ONE_MINUTE).until(() -> { + await().atMost(Duration.ofMinutes(1)).until(() -> { status.clear(); status.addAll(logRepository.getMessageStatus(messageMetadata.getTopic(), messageMetadata.getSubscription(), messageMetadata.getMessageId())); diff --git a/hermes-tracker/src/main/java/pl/allegro/tech/hermes/tracker/QueueCommitter.java b/hermes-tracker/src/main/java/pl/allegro/tech/hermes/tracker/QueueCommitter.java index 3bae8d6131..51056ba5e4 100644 --- a/hermes-tracker/src/main/java/pl/allegro/tech/hermes/tracker/QueueCommitter.java +++ b/hermes-tracker/src/main/java/pl/allegro/tech/hermes/tracker/QueueCommitter.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.tracker; -import com.codahale.metrics.Timer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pl.allegro.tech.hermes.metrics.HermesTimer; diff --git a/hermes-tracker/src/test/java/pl/allegro/tech/hermes/tracker/consumers/AbstractLogRepositoryTest.java b/hermes-tracker/src/test/java/pl/allegro/tech/hermes/tracker/consumers/AbstractLogRepositoryTest.java index 8bc4b6fa2d..9144196063 100644 --- a/hermes-tracker/src/test/java/pl/allegro/tech/hermes/tracker/consumers/AbstractLogRepositoryTest.java +++ b/hermes-tracker/src/test/java/pl/allegro/tech/hermes/tracker/consumers/AbstractLogRepositoryTest.java @@ -1,35 +1,21 @@ package pl.allegro.tech.hermes.tracker.consumers; -import org.testng.ITestContext; -import org.testng.ITestNGMethod; -import org.testng.annotations.BeforeSuite; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; +import org.junit.Before; +import org.junit.Test; import pl.allegro.tech.hermes.api.SentMessageTraceStatus; -import pl.allegro.tech.hermes.test.helper.retry.Retry; -import pl.allegro.tech.hermes.test.helper.retry.RetryListener; import static pl.allegro.tech.hermes.api.SentMessageTraceStatus.DISCARDED; import static pl.allegro.tech.hermes.api.SentMessageTraceStatus.INFLIGHT; import static pl.allegro.tech.hermes.api.SentMessageTraceStatus.SUCCESS; -@Listeners({RetryListener.class}) public abstract class AbstractLogRepositoryTest { private static final String SUBSCRIPTION = "subscription"; private LogRepository logRepository; - @BeforeSuite - public void setUpRetry(ITestContext context) { - for (ITestNGMethod method : context.getAllTestMethods()) { - method.setRetryAnalyzerClass(Retry.class); - } - } - - @BeforeTest - public void setUp() throws Exception { + @Before + public void setUp() { logRepository = createLogRepository(); } diff --git a/hermes-tracker/src/test/java/pl/allegro/tech/hermes/tracker/frontend/AbstractLogRepositoryTest.java b/hermes-tracker/src/test/java/pl/allegro/tech/hermes/tracker/frontend/AbstractLogRepositoryTest.java index a609522a57..8ec5d8ff22 100644 --- a/hermes-tracker/src/test/java/pl/allegro/tech/hermes/tracker/frontend/AbstractLogRepositoryTest.java +++ b/hermes-tracker/src/test/java/pl/allegro/tech/hermes/tracker/frontend/AbstractLogRepositoryTest.java @@ -1,32 +1,18 @@ package pl.allegro.tech.hermes.tracker.frontend; import com.google.common.collect.ImmutableMap; -import org.testng.ITestContext; -import org.testng.ITestNGMethod; -import org.testng.annotations.BeforeSuite; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; -import pl.allegro.tech.hermes.test.helper.retry.Retry; -import pl.allegro.tech.hermes.test.helper.retry.RetryListener; +import org.junit.Before; +import org.junit.Test; import java.util.Map; import static java.lang.System.currentTimeMillis; -@Listeners({RetryListener.class}) public abstract class AbstractLogRepositoryTest { private LogRepository logRepository; - @BeforeSuite - public void setUpRetry(ITestContext context) { - for (ITestNGMethod method : context.getAllTestMethods()) { - method.setRetryAnalyzerClass(Retry.class); - } - } - - @BeforeTest + @Before public void setup() { logRepository = createRepository(); } @@ -80,13 +66,13 @@ public void shouldLogInflight() throws Exception { } protected abstract void awaitUntilSuccessMessageIsPersisted( - String topic, - String id, - String remoteHostname, - String storageDatacenter, - String... extraRequestHeadersKeywords + String topic, + String id, + String remoteHostname, + String storageDatacenter, + String... extraRequestHeadersKeywords ) - throws Exception; + throws Exception; protected abstract void awaitUntilInflightMessageIsPersisted( String topic, @@ -98,11 +84,11 @@ protected abstract void awaitUntilInflightMessageIsPersisted( protected abstract void awaitUntilErrorMessageIsPersisted( - String topic, - String id, - String reason, - String remoteHostname, - String... extraRequestHeadersKeywords + String topic, + String id, + String reason, + String remoteHostname, + String... extraRequestHeadersKeywords ) - throws Exception; + throws Exception; } \ No newline at end of file diff --git a/integration-tests/build.gradle b/integration-tests/build.gradle index 12df7da2e9..19fca04359 100644 --- a/integration-tests/build.gradle +++ b/integration-tests/build.gradle @@ -16,9 +16,10 @@ dependencies { testImplementation group: 'com.squareup.okhttp3', name: 'okhttp', version: versions.okhttp testImplementation group: 'org.springframework', name: 'spring-webflux', version: versions.spring_web testImplementation group: 'org.springframework', name: 'spring-test', version: versions.spring_web - testImplementation group: 'org.eclipse.jetty', name: 'jetty-reactive-httpclient', version: '4.0.2' + testImplementation group: 'org.eclipse.jetty', name: 'jetty-reactive-httpclient', version: '4.0.3' testImplementation group: 'org.awaitility', name: 'awaitility', version: '4.2.0' testImplementation group: 'org.reactivestreams', name: 'reactive-streams', version: '1.0.4' + // TODO: can we update it ? Which version of server our clients use ? testImplementation(group: 'org.hornetq', name: 'hornetq-jms-server', version: '2.4.1.Final') { exclude module: 'hornetq-native' } diff --git a/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesConsumersTestApp.java b/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesConsumersTestApp.java index e7d0541776..f6151023e0 100644 --- a/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesConsumersTestApp.java +++ b/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesConsumersTestApp.java @@ -77,7 +77,6 @@ private List createArgs() { "--consumer.commit.offset.period=" + Duration.ofSeconds(1), "--consumer.metrics.micrometer.reportPeriod=" + Duration.ofSeconds(5), "--consumer.schema.cache.enabled=true", - "--consumer.metrics.metric-registry.graphiteReporterEnabled=false", "--consumer.google.pubsub.sender.transportChannelProviderAddress=" + getGooglePubSubEndpoint() ); } diff --git a/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesExtension.java b/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesExtension.java index 7f1ce40cef..ff1e4bb4ed 100644 --- a/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesExtension.java +++ b/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesExtension.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.integrationtests.setup; -import com.jayway.awaitility.Duration; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.extension.AfterAllCallback; import org.junit.jupiter.api.extension.BeforeAllCallback; @@ -27,10 +26,11 @@ import pl.allegro.tech.hermes.test.helper.containers.ZookeeperContainer; import pl.allegro.tech.hermes.test.helper.environment.HermesTestApp; +import java.time.Duration; import java.util.List; import java.util.stream.Stream; -import static com.jayway.awaitility.Awaitility.waitAtMost; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.integrationtests.setup.HermesManagementTestApp.AUDIT_EVENT_PATH; import static pl.allegro.tech.hermes.test.helper.endpoint.TimeoutAdjuster.adjust; @@ -113,7 +113,7 @@ private void removeSubscriptions() { service.removeSubscription(subscription.getTopicName(), subscription.getName(), testUser); } - waitAtMost(adjust(Duration.ONE_MINUTE)).until(() -> + waitAtMost(adjust(Duration.ofMinutes(1))).untilAsserted(() -> Assertions.assertThat(service.getAllSubscriptions().size()).isEqualTo(0) ); } @@ -125,7 +125,7 @@ private void removeTopics() { service.removeTopicWithSchema(topic, testUser); } - waitAtMost(adjust(Duration.ONE_MINUTE)).until(() -> + waitAtMost(adjust(Duration.ofMinutes(1))).untilAsserted(() -> Assertions.assertThat(service.getAllTopics().size()).isEqualTo(0) ); } diff --git a/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesFrontendTestApp.java b/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesFrontendTestApp.java index 5a4aa9d67c..2a13efbaa9 100644 --- a/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesFrontendTestApp.java +++ b/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesFrontendTestApp.java @@ -111,7 +111,7 @@ private List createArgs() { args.put(KAFKA_PRODUCER_METADATA_MAX_AGE, metadataMaxAge); - args.put(FRONTEND_FORCE_TOPIC_MAX_MESSAGE_SIZE,true); + args.put(FRONTEND_FORCE_TOPIC_MAX_MESSAGE_SIZE, true); args.put(FRONTEND_IDLE_TIMEOUT, Duration.ofSeconds(2)); args.put(FRONTEND_THROUGHPUT_TYPE, "fixed"); diff --git a/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesManagementTestApp.java b/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesManagementTestApp.java index ffacfc1430..16ebf4bbe5 100644 --- a/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesManagementTestApp.java +++ b/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/setup/HermesManagementTestApp.java @@ -23,8 +23,8 @@ import java.util.Map; import java.util.concurrent.TimeUnit; -import static com.jayway.awaitility.Awaitility.waitAtMost; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.infrastructure.dc.DefaultDatacenterNameProvider.DEFAULT_DC_NAME; import static pl.allegro.tech.hermes.test.helper.endpoint.TimeoutAdjuster.adjust; @@ -79,7 +79,7 @@ private void waitUntilReady() { .build(); HttpClient httpClient = HttpClient.newHttpClient(); - waitAtMost(adjust(240), TimeUnit.SECONDS).until(() -> { + waitAtMost(adjust(240), TimeUnit.SECONDS).untilAsserted(() -> { try { HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); assertThat(response.body()).isEqualTo("readWrite"); diff --git a/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/subscriber/TestJmsSubscriber.java b/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/subscriber/TestJmsSubscriber.java index b99c97d766..dabfedda37 100644 --- a/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/subscriber/TestJmsSubscriber.java +++ b/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/subscriber/TestJmsSubscriber.java @@ -1,24 +1,23 @@ package pl.allegro.tech.hermes.integrationtests.subscriber; -import com.jayway.awaitility.Duration; import org.hornetq.api.core.TransportConfiguration; import org.hornetq.api.jms.HornetQJMSClient; import org.hornetq.api.jms.JMSFactoryType; import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import javax.jms.ConnectionFactory; import javax.jms.JMSContext; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.Topic; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import static com.jayway.awaitility.Awaitility.await; -import static java.util.concurrent.TimeUnit.SECONDS; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import static pl.allegro.tech.hermes.test.helper.endpoint.TimeoutAdjuster.adjust; public class TestJmsSubscriber { @@ -80,7 +79,7 @@ public void waitUntilMessageWithHeaderReceived(String headerName, String headerV } private void awaitWithSyncRequests(Runnable runnable) { - await().atMost(adjust(new Duration(DEFAULT_WAIT_TIME_IN_SEC, SECONDS))).until(() -> { + await().atMost(adjust(Duration.ofSeconds(DEFAULT_WAIT_TIME_IN_SEC))).untilAsserted(() -> { synchronized (receivedRequests) { runnable.run(); } diff --git a/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/subscriber/TestSubscriber.java b/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/subscriber/TestSubscriber.java index d502051294..59d2ace7fa 100644 --- a/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/subscriber/TestSubscriber.java +++ b/integration-tests/src/common/java/pl/allegro/tech/hermes/integrationtests/subscriber/TestSubscriber.java @@ -2,9 +2,9 @@ import com.github.tomakehurst.wiremock.verification.LoggedRequest; import com.google.common.collect.Streams; -import com.jayway.awaitility.Duration; import java.net.URI; +import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -13,9 +13,8 @@ import java.util.function.Consumer; import java.util.stream.Collectors; -import static com.jayway.awaitility.Awaitility.await; -import static java.util.concurrent.TimeUnit.SECONDS; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import static pl.allegro.tech.hermes.test.helper.endpoint.TimeoutAdjuster.adjust; public class TestSubscriber { @@ -53,15 +52,16 @@ public void waitUntilReceived(String body) { ).isNotEmpty()); } - public void waitUntilAnyMessageReceived() { - await().atMost(adjust(new Duration(DEFAULT_WAIT_TIME_IN_SEC, SECONDS))).until(() -> - assertThat(receivedRequests.size()).isPositive()); - } public void waitUntilReceived(Duration duration, int numberOfExpectedMessages) { - await().atMost(adjust(duration)).until(() -> + await().atMost(adjust(duration)).untilAsserted(() -> assertThat(receivedRequests.size()).isEqualTo(numberOfExpectedMessages)); } + public void waitUntilAnyMessageReceived() { + await().atMost(adjust(Duration.ofSeconds(DEFAULT_WAIT_TIME_IN_SEC))).untilAsserted(() -> + assertThat(receivedRequests.size()).isPositive()); + } + public void waitUntilRequestReceived(Consumer requestConsumer) { waitUntilAnyMessageReceived(); @@ -71,7 +71,7 @@ public void waitUntilRequestReceived(Consumer requestConsumer) { } public void waitUntilRequestsReceived(Consumer> requestsConsumer) { - await().atMost(adjust(new Duration(DEFAULT_WAIT_TIME_IN_SEC, SECONDS))).until( + await().atMost(adjust(Duration.ofSeconds(DEFAULT_WAIT_TIME_IN_SEC))).untilAsserted( () -> { synchronized (receivedRequests) { requestsConsumer.accept(receivedRequests); @@ -100,7 +100,7 @@ public java.time.Duration durationBetweenFirstAndLastRequest() { } private void awaitWithSyncRequests(Runnable runnable) { - await().atMost(adjust(new Duration(DEFAULT_WAIT_TIME_IN_SEC, SECONDS))).until(() -> { + await().atMost(adjust(Duration.ofSeconds(DEFAULT_WAIT_TIME_IN_SEC))).untilAsserted(() -> { synchronized (receivedRequests) { runnable.run(); } diff --git a/integration-tests/src/common/java/pl/allegro/tech/hermes/management/TestSecurityProvider.java b/integration-tests/src/common/java/pl/allegro/tech/hermes/management/TestSecurityProvider.java index 80553233f4..afcc375b62 100644 --- a/integration-tests/src/common/java/pl/allegro/tech/hermes/management/TestSecurityProvider.java +++ b/integration-tests/src/common/java/pl/allegro/tech/hermes/management/TestSecurityProvider.java @@ -2,7 +2,7 @@ import jakarta.ws.rs.container.ContainerRequestContext; import jakarta.ws.rs.core.SecurityContext; -import org.apache.commons.lang.NotImplementedException; +import org.apache.commons.lang3.NotImplementedException; import pl.allegro.tech.hermes.api.OwnerId; import pl.allegro.tech.hermes.management.api.auth.SecurityProvider; diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/BatchDeliveryTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/BatchDeliveryTest.java index bbf7d0f26e..1a700ebe59 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/BatchDeliveryTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/BatchDeliveryTest.java @@ -1,7 +1,6 @@ package pl.allegro.tech.hermes.integrationtests; import com.fasterxml.jackson.databind.ObjectMapper; -import com.jayway.awaitility.Duration; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -16,6 +15,7 @@ import pl.allegro.tech.hermes.test.helper.message.TestMessage; import java.io.IOException; +import java.time.Duration; import java.util.List; import java.util.Map; @@ -297,7 +297,7 @@ public void shouldTimeoutRequestToSlowlyRespondingClient() { // then // first request is retried because of timeout (with socket / idle timeout only, the request wouldn't be timed out because // there are chunks of response every 500ms which is smaller than 1s timeout) - subscriber.waitUntilReceived(Duration.FIVE_SECONDS, 2); + subscriber.waitUntilReceived(Duration.ofSeconds(5), 2); Assertions.assertThat(subscriber.getLastReceivedRequest().getHeader("Hermes-Retry-Count")).isEqualTo("1"); } diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/BatchRetryPolicyTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/BatchRetryPolicyTest.java index eefa8aeceb..77c9a42074 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/BatchRetryPolicyTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/BatchRetryPolicyTest.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.tomakehurst.wiremock.stubbing.Scenario; import com.github.tomakehurst.wiremock.verification.LoggedRequest; -import com.jayway.awaitility.Duration; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -17,15 +16,16 @@ import pl.allegro.tech.hermes.test.helper.message.TestMessage; import java.io.IOException; +import java.time.Duration; import java.util.List; import java.util.Map; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.containing; import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static org.apache.http.HttpStatus.SC_BAD_REQUEST; -import static org.apache.http.HttpStatus.SC_CREATED; -import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; +import static org.apache.hc.core5.http.HttpStatus.SC_BAD_REQUEST; +import static org.apache.hc.core5.http.HttpStatus.SC_CREATED; +import static org.apache.hc.core5.http.HttpStatus.SC_INTERNAL_SERVER_ERROR; import static pl.allegro.tech.hermes.api.BatchSubscriptionPolicy.Builder.batchSubscriptionPolicy; import static pl.allegro.tech.hermes.test.helper.builder.SubscriptionBuilder.subscription; import static pl.allegro.tech.hermes.test.helper.builder.TopicBuilder.topicWithRandomName; @@ -91,7 +91,7 @@ public void shouldNotRetryIfRequestSuccessful() { hermes.api().publishUntilSuccess(topic.getQualifiedName(), message.body()); //then - subscriber.waitUntilReceived(Duration.FIVE_SECONDS, 1); + subscriber.waitUntilReceived(Duration.ofSeconds(5), 1); } @Test diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/BroadcastDeliveryTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/BroadcastDeliveryTest.java index 699d64d5d0..b6c51c3903 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/BroadcastDeliveryTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/BroadcastDeliveryTest.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.integrationtests; -import com.jayway.awaitility.Duration; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -14,14 +13,14 @@ import pl.allegro.tech.hermes.integrationtests.subscriber.TestSubscribersExtension; import pl.allegro.tech.hermes.test.helper.message.TestMessage; +import java.time.Duration; import java.util.List; import java.util.stream.Stream; -import static com.jayway.awaitility.Awaitility.waitAtMost; -import static com.jayway.awaitility.Duration.TEN_SECONDS; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.api.SubscriptionPolicy.Builder.subscriptionPolicy; import static pl.allegro.tech.hermes.test.helper.builder.SubscriptionBuilder.subscription; import static pl.allegro.tech.hermes.test.helper.builder.TopicBuilder.topicWithRandomName; @@ -75,7 +74,7 @@ public void shouldPublishAndRetryOnlyForUndeliveredConsumers() { // then subscribers.forEach(s -> s.waitUntilReceived(message.body())); - retryingSubscriber.waitUntilReceived(Duration.ONE_MINUTE, 2); + retryingSubscriber.waitUntilReceived(Duration.ofMinutes(1), 2); Assertions.assertThat(retryingSubscriber.getLastReceivedRequest().getHeader("Hermes-Retry-Count")).isEqualTo("1"); } @@ -100,7 +99,7 @@ public void shouldNotRetryForBadRequestsFromConsumers() { // then subscribers.forEach(s -> s.waitUntilReceived(message.body())); - waitAtMost(TEN_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { long discarded = hermes.api() .getSubscriptionMetrics(topic.getQualifiedName(), "subscription") .expectBody(SubscriptionMetrics.class).returnResult().getResponseBody().getDiscarded(); diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/ConsumerProfilingTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/ConsumerProfilingTest.java new file mode 100644 index 0000000000..64148f67d0 --- /dev/null +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/ConsumerProfilingTest.java @@ -0,0 +1,247 @@ +package pl.allegro.tech.hermes.integrationtests; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.slf4j.LoggerFactory; +import pl.allegro.tech.hermes.api.Subscription; +import pl.allegro.tech.hermes.api.Topic; +import pl.allegro.tech.hermes.consumers.consumer.profiling.ConsumerRun; +import pl.allegro.tech.hermes.consumers.consumer.profiling.DefaultConsumerProfiler; +import pl.allegro.tech.hermes.consumers.consumer.profiling.Measurement; +import pl.allegro.tech.hermes.integrationtests.setup.HermesExtension; +import pl.allegro.tech.hermes.integrationtests.subscriber.TestSubscriber; +import pl.allegro.tech.hermes.integrationtests.subscriber.TestSubscribersExtension; +import pl.allegro.tech.hermes.test.helper.message.TestMessage; + +import java.time.Duration; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; +import static pl.allegro.tech.hermes.test.helper.builder.SubscriptionBuilder.subscriptionWithRandomName; +import static pl.allegro.tech.hermes.test.helper.builder.TopicBuilder.topicWithRandomName; + +public class ConsumerProfilingTest { + + @RegisterExtension + public static final HermesExtension hermes = new HermesExtension(); + + @RegisterExtension + public static final TestSubscribersExtension subscribers = new TestSubscribersExtension(); + + private ListAppender listAppender; + + @BeforeEach + void createLogAppender() { + Logger logWatcher = (Logger) LoggerFactory.getLogger(DefaultConsumerProfiler.class); + + listAppender = new ListAppender<>(); + listAppender.start(); + + logWatcher.addAppender(listAppender); + } + + @AfterEach + void teardown() { + ((Logger) LoggerFactory.getLogger(DefaultConsumerProfiler.class)).detachAndStopAllAppenders(); + hermes.clearManagementData(); + } + + @AfterAll + static void teardownClass() { + hermes.clearManagementData(); + } + + @Test + public void shouldNotProfileWhenProfilingIsDisabled() { + // given + TestSubscriber subscriber = subscribers.createSubscriber(); + Topic topic = hermes.initHelper().createTopic(topicWithRandomName().build()); + Subscription subscription = hermes.initHelper().createSubscription(subscriptionWithRandomName(topic.getName(), subscriber.getEndpoint()) + .withProfilingEnabled(false).build()); + TestMessage message = TestMessage.random(); + hermes.api().publishUntilSuccess(topic.getQualifiedName(), message.body()); + + // when + subscriber.waitUntilReceived(message.body()); + + // then + List logsList = listAppender.list.stream() + .filter(log -> log.getFormattedMessage().contains(subscription.getQualifiedName().toString())).toList(); + assertThat(logsList).hasSize(0); + } + + @Test + public void shouldProfileEmptyRun() { + // given + Topic topic = hermes.initHelper().createTopic(topicWithRandomName().build()); + + // when + Subscription subscription = hermes.initHelper().createSubscription(subscriptionWithRandomName(topic.getName()) + .withProfilingEnabled(true).build()); + + // then + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { + List logsList = listAppender.list.stream() + .filter(log -> log.getFormattedMessage().contains(subscription.getQualifiedName().toString())).toList(); + assertThat(logsList).hasSizeGreaterThan(0); + assertThat(logsList.get(0).getFormattedMessage()).contains( + String.format("Consumer profiler measurements for subscription %s and %s run:", subscription.getQualifiedName(), ConsumerRun.EMPTY), + Measurement.SIGNALS_AND_SEMAPHORE_ACQUIRE, + Measurement.MESSAGE_RECEIVER_NEXT, + Measurement.MESSAGE_CONVERSION, + "partialMeasurements", + Measurement.SIGNALS_INTERRUPT_RUN + ); + }); + } + + @Test + public void shouldNotProfileRunsBelowThreshold() { + // given + TestSubscriber subscriber = subscribers.createSubscriber(); + Topic topic = hermes.initHelper().createTopic(topicWithRandomName().build()); + Subscription subscription = hermes.initHelper().createSubscription(subscriptionWithRandomName(topic.getName(), subscriber.getEndpoint()) + .withProfilingEnabled(true) + .withProfilingThresholdMs(100_000) + .build()); + TestMessage message = TestMessage.random(); + hermes.api().publishUntilSuccess(topic.getQualifiedName(), message.body()); + + // when + subscriber.waitUntilReceived(message.body()); + + // then + List logsList = listAppender.list.stream() + .filter(log -> log.getFormattedMessage().contains(subscription.getQualifiedName().toString())).toList(); + assertThat(logsList).hasSize(0); + } + + @Test + public void shouldProfileSuccessfulMessageProcessing() { + // given + TestSubscriber subscriber = subscribers.createSubscriber(); + Topic topic = hermes.initHelper().createTopic(topicWithRandomName().build()); + Subscription subscription = hermes.initHelper().createSubscription(subscriptionWithRandomName(topic.getName(), subscriber.getEndpoint()) + .withProfilingEnabled(true).build()); + TestMessage message = TestMessage.random(); + hermes.api().publishUntilSuccess(topic.getQualifiedName(), message.body()); + + // when + subscriber.waitUntilReceived(message.body()); + + // then + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { + List logsList = listAppender.list.stream() + .filter(log -> log.getFormattedMessage().contains(ConsumerRun.DELIVERED.name())).toList(); + assertThat(logsList).hasSizeGreaterThan(0); + assertThat(logsList.get(0).getFormattedMessage()).contains( + String.format("Consumer profiler measurements for subscription %s and %s run:", subscription.getQualifiedName(), ConsumerRun.DELIVERED), + Measurement.SIGNALS_AND_SEMAPHORE_ACQUIRE, + Measurement.MESSAGE_RECEIVER_NEXT, + Measurement.MESSAGE_CONVERSION, + Measurement.OFFER_INFLIGHT_OFFSET, + Measurement.TRACKERS_LOG_INFLIGHT, + Measurement.SCHEDULE_MESSAGE_SENDING, + Measurement.ACQUIRE_RATE_LIMITER, + Measurement.MESSAGE_SENDER_SEND, + Measurement.HANDLERS, + "partialMeasurements", + Measurement.SIGNALS_INTERRUPT_RUN + ); + }); + } + + @Test + public void shouldProfileDiscardedMessageProcessing() { + // given + Topic topic = hermes.initHelper().createTopic(topicWithRandomName().build()); + TestSubscriber subscriber = subscribers.createSubscriber(400); + Subscription subscription = hermes.initHelper().createSubscription(subscriptionWithRandomName(topic.getName(), subscriber.getEndpoint()) + .withProfilingEnabled(true) + .build()); + TestMessage message = TestMessage.random(); + hermes.api().publishUntilSuccess(topic.getQualifiedName(), message.body()); + + // when + subscriber.waitUntilReceived(message.body()); + + // then + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { + List logsList = listAppender.list.stream() + .filter(log -> log.getFormattedMessage().contains(ConsumerRun.DISCARDED.name())).toList(); + assertThat(logsList).hasSizeGreaterThan(0); + assertThat(logsList.get(0).getFormattedMessage()).contains( + String.format("Consumer profiler measurements for subscription %s and %s run:", subscription.getQualifiedName(), ConsumerRun.DISCARDED), + Measurement.SIGNALS_AND_SEMAPHORE_ACQUIRE, + Measurement.MESSAGE_RECEIVER_NEXT, + Measurement.MESSAGE_CONVERSION, + Measurement.OFFER_INFLIGHT_OFFSET, + Measurement.TRACKERS_LOG_INFLIGHT, + Measurement.SCHEDULE_MESSAGE_SENDING, + Measurement.ACQUIRE_RATE_LIMITER, + Measurement.MESSAGE_SENDER_SEND, + Measurement.HANDLERS, + "partialMeasurements", + Measurement.SIGNALS_INTERRUPT_RUN + ); + }); + } + + @Test + public void shouldProfileRetriedMessageProcessing() { + // given + Topic topic = hermes.initHelper().createTopic(topicWithRandomName().build()); + TestMessage message = TestMessage.random(); + TestSubscriber subscriber = subscribers.createSubscriberWithRetry(message.body(), 1); + Subscription subscription = hermes.initHelper().createSubscription(subscriptionWithRandomName(topic.getName(), subscriber.getEndpoint()) + .withProfilingEnabled(true) + .build()); + hermes.api().publishUntilSuccess(topic.getQualifiedName(), message.body()); + + // when + subscriber.waitUntilReceived(Duration.ofSeconds(5), 2); + + // then + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { + List retriedLogsList = listAppender.list.stream() + .filter(log -> log.getFormattedMessage().contains(ConsumerRun.RETRIED.name())).toList(); + assertThat(retriedLogsList).hasSizeGreaterThan(0); + assertThat(retriedLogsList.get(0).getFormattedMessage()).contains( + String.format("Consumer profiler measurements for subscription %s and %s run:", subscription.getQualifiedName(), ConsumerRun.RETRIED), + Measurement.SIGNALS_AND_SEMAPHORE_ACQUIRE, + Measurement.MESSAGE_RECEIVER_NEXT, + Measurement.MESSAGE_CONVERSION, + Measurement.OFFER_INFLIGHT_OFFSET, + Measurement.TRACKERS_LOG_INFLIGHT, + Measurement.SCHEDULE_MESSAGE_SENDING, + Measurement.ACQUIRE_RATE_LIMITER, + Measurement.MESSAGE_SENDER_SEND, + Measurement.HANDLERS, + "partialMeasurements", + Measurement.SIGNALS_INTERRUPT_RUN + ); + }); + + + // and + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { + List processedLogsList = listAppender.list.stream() + .filter(log -> log.getFormattedMessage().contains(ConsumerRun.DELIVERED.name())).toList(); + assertThat(processedLogsList).hasSizeGreaterThan(0); + assertThat(processedLogsList.get(0).getFormattedMessage()).contains( + String.format("Consumer profiler measurements for subscription %s and %s run:", subscription.getQualifiedName(), ConsumerRun.DELIVERED), + Measurement.SCHEDULE_RESEND, + Measurement.MESSAGE_SENDER_SEND, + Measurement.HANDLERS, + "retryDelayMillis 1000" + ); + }); + } +} diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/KafkaProducerMetricsTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/KafkaProducerMetricsTest.java index 5f3a98a155..71555d636d 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/KafkaProducerMetricsTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/KafkaProducerMetricsTest.java @@ -8,7 +8,7 @@ import java.util.concurrent.TimeUnit; -import static com.jayway.awaitility.Awaitility.await; +import static org.awaitility.Awaitility.await; import static pl.allegro.tech.hermes.integrationtests.assertions.HermesAssertions.assertThatMetrics; import static pl.allegro.tech.hermes.test.helper.builder.TopicBuilder.topicWithRandomName; @@ -28,7 +28,7 @@ public void shouldRegisterSendMetrics() { hermes.api().publish(topic.getQualifiedName(), "hello world"); // then - await().atMost(10, TimeUnit.SECONDS).until(() -> + await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> assertMetricsContainTotalSendMetric().withValue(initialMetricValue + 2.0)); } diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/KafkaRetransmissionServiceTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/KafkaRetransmissionServiceTest.java index 883e408a87..513d3e39c2 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/KafkaRetransmissionServiceTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/KafkaRetransmissionServiceTest.java @@ -2,7 +2,6 @@ import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.Multimaps; -import com.jayway.awaitility.Duration; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.test.web.reactive.server.WebTestClient; @@ -21,15 +20,16 @@ import pl.allegro.tech.hermes.test.helper.message.TestMessage; import java.time.Clock; +import java.time.Duration; import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; -import static com.jayway.awaitility.Awaitility.waitAtMost; import static java.util.stream.IntStream.range; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.api.PatchData.patchData; import static pl.allegro.tech.hermes.consumers.supervisor.process.Signal.SignalType.COMMIT; import static pl.allegro.tech.hermes.test.helper.builder.SubscriptionBuilder.subscriptionWithRandomName; @@ -155,7 +155,7 @@ private void publishAndConsumeMessages(List messages, Topic topic, TestS private void waitUntilConsumerCommitsOffset(String topicQualifiedName, String subscription) { long currentTime = clock.millis(); - until(Duration.ONE_MINUTE, topicQualifiedName, subscription, sub -> + until(Duration.ofMinutes(1), topicQualifiedName, subscription, sub -> sub.getSignalTimesheet().getOrDefault(COMMIT, 0L) > currentTime); } diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/MetricsTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/MetricsTest.java index caf42ae534..a10cec2ba3 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/MetricsTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/MetricsTest.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.integrationtests; -import com.jayway.awaitility.Duration; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -20,12 +19,13 @@ import pl.allegro.tech.hermes.integrationtests.subscriber.TestSubscribersExtension; import pl.allegro.tech.hermes.test.helper.message.TestMessage; +import java.time.Duration; import java.util.Map; import java.util.UUID; -import static com.jayway.awaitility.Awaitility.waitAtMost; import static java.lang.Integer.MAX_VALUE; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.api.BatchSubscriptionPolicy.Builder.batchSubscriptionPolicy; import static pl.allegro.tech.hermes.api.SubscriptionPolicy.Builder.subscriptionPolicy; import static pl.allegro.tech.hermes.integrationtests.assertions.HermesAssertions.assertThatMetrics; @@ -61,7 +61,7 @@ public void shouldIncreaseTopicMetricsAfterMessageHasBeenPublished() { TestMessage message = TestMessage.simple(); int attempts = hermes.api().publishUntilSuccess(topic.getQualifiedName(), message.body()); - waitAtMost(Duration.TEN_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { // when WebTestClient.ResponseSpec response = hermes.api().getTopicMetrics(topic.getQualifiedName()); @@ -87,7 +87,7 @@ public void shouldIncreaseSubscriptionDeliveredMetricsAfterMessageDelivered() { hermes.api().publishUntilSuccess(topic.getQualifiedName(), message.body()); subscriber.waitUntilReceived(message.body()); - waitAtMost(Duration.TEN_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { // when WebTestClient.ResponseSpec response = hermes.api().getSubscriptionMetrics(topic.getQualifiedName(), subscription.getName()); @@ -240,19 +240,21 @@ public void shouldReportMetricForFilteredSubscription() { // then subscriber.waitUntilReceived(unfiltered.body()); - hermes.api().getConsumersMetrics() - .expectStatus() - .isOk() - .expectBody(String.class) - .value((body) -> assertThatMetrics(body) - .contains("hermes_consumers_subscription_filtered_out_total") - .withLabels( - "group", topic.getName().getGroupName(), - "subscription", subscription.getName(), - "topic", topic.getName().getName() + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> + hermes.api().getConsumersMetrics() + .expectStatus() + .isOk() + .expectBody(String.class) + .value((body) -> assertThatMetrics(body) + .contains("hermes_consumers_subscription_filtered_out_total") + .withLabels( + "group", topic.getName().getGroupName(), + "subscription", subscription.getName(), + "topic", topic.getName().getName() + ) + .withValue(1.0) ) - .withValue(1.0) - ); + ); } @Test diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/OAuthIntegrationTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/OAuthIntegrationTest.java index be76f491ef..886cd85e45 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/OAuthIntegrationTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/OAuthIntegrationTest.java @@ -18,8 +18,8 @@ import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.not; import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static org.apache.http.HttpStatus.SC_OK; -import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; +import static org.apache.hc.core5.http.HttpStatus.SC_OK; +import static org.apache.hc.core5.http.HttpStatus.SC_UNAUTHORIZED; import static pl.allegro.tech.hermes.api.SubscriptionOAuthPolicy.clientCredentialsGrantOAuthPolicy; import static pl.allegro.tech.hermes.api.SubscriptionOAuthPolicy.passwordGrantOAuthPolicy; import static pl.allegro.tech.hermes.test.helper.builder.OAuthProviderBuilder.oAuthProvider; diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingAndConsumingTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingAndConsumingTest.java index 940cded8c9..f154ff77da 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingAndConsumingTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingAndConsumingTest.java @@ -26,9 +26,8 @@ import java.util.Map; import java.util.UUID; -import static com.jayway.awaitility.Awaitility.waitAtMost; -import static com.jayway.awaitility.Duration.TEN_SECONDS; import static jakarta.ws.rs.core.Response.Status.CREATED; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.api.SubscriptionPolicy.Builder.subscriptionPolicy; import static pl.allegro.tech.hermes.integrationtests.assertions.HermesAssertions.assertThat; import static pl.allegro.tech.hermes.test.helper.builder.SubscriptionBuilder.subscription; @@ -110,7 +109,7 @@ public void shouldTreatMessageWithInvalidInterpolationAsUndelivered() { hermes.api().publishUntilSuccess(topic.getQualifiedName(), message.body()); // then - waitAtMost(TEN_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { long discarded = hermes.api() .getSubscriptionMetrics(topic.getQualifiedName(), "subscription") .expectBody(SubscriptionMetrics.class).returnResult().getResponseBody().getDiscarded(); diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingAuthenticationTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingAuthenticationTest.java index e3838f6b77..fb6ec99094 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingAuthenticationTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingAuthenticationTest.java @@ -1,7 +1,5 @@ package pl.allegro.tech.hermes.integrationtests; -import com.jayway.awaitility.Duration; -import org.apache.commons.codec.binary.Base64; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.http.HttpHeaders; @@ -12,9 +10,11 @@ import pl.allegro.tech.hermes.utils.Headers; import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.Base64; import java.util.Map; -import static com.jayway.awaitility.Awaitility.waitAtMost; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.frontend.FrontendConfigurationProperties.AUTH_PASSWORD; import static pl.allegro.tech.hermes.frontend.FrontendConfigurationProperties.AUTH_USERNAME; import static pl.allegro.tech.hermes.frontend.FrontendConfigurationProperties.FRONTEND_AUTHENTICATION_ENABLED; @@ -42,7 +42,7 @@ public void shouldAuthenticateUsingBasicAuth() { //given Topic topic = hermes.initHelper().createTopic(topicWithRandomName().build()); - waitAtMost(Duration.TEN_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { // when WebTestClient.ResponseSpec response = hermes.api().publish( topic.getQualifiedName(), @@ -60,7 +60,7 @@ public void shouldNotAuthenticateUserWithInvalidCredentials() { //given Topic topic = hermes.initHelper().createTopic(topicWithRandomName().build()); - waitAtMost(Duration.TEN_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { // when WebTestClient.ResponseSpec response = hermes.api().publish( topic.getQualifiedName(), @@ -78,7 +78,7 @@ public void shouldNotAuthenticateUserWithoutCredentials() { //given Topic topic = hermes.initHelper().createTopic(topicWithRandomName().build()); - waitAtMost(Duration.TEN_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { // when WebTestClient.ResponseSpec response = hermes.api().publish(topic.getQualifiedName(), MESSAGE); @@ -90,7 +90,7 @@ public void shouldNotAuthenticateUserWithoutCredentials() { private static HttpHeaders createAuthorizationHeader(String username, String password) { String credentials = username + ":" + password; Map headers = Map.of( - "Authorization", "Basic " + Base64.encodeBase64String(credentials.getBytes(StandardCharsets.UTF_8)) + "Authorization", "Basic " + Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8)) ); return Headers.createHeaders(headers); } diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingAvroTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingAvroTest.java index c89dbf5070..dcf6cb2a05 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingAvroTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingAvroTest.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.integrationtests; -import com.jayway.awaitility.Duration; import net.javacrumbs.jsonunit.core.Option; import org.apache.avro.Schema; import org.junit.jupiter.api.Test; @@ -22,14 +21,15 @@ import pl.allegro.tech.hermes.test.helper.message.TestMessage; import java.time.Clock; +import java.time.Duration; import java.util.Map; import java.util.UUID; -import static com.jayway.awaitility.Awaitility.waitAtMost; import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN; import static java.util.Collections.singletonMap; import static net.javacrumbs.jsonunit.fluent.JsonFluentAssert.assertThatJson; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.api.AvroMediaType.AVRO_JSON; import static pl.allegro.tech.hermes.api.ContentType.AVRO; import static pl.allegro.tech.hermes.api.ContentType.JSON; @@ -227,7 +227,7 @@ public void shouldGetBadRequestForJsonNotMatchingWithAvroSchemaAndAvroContentTyp String message = "{\"__metadata\":null,\"name\":\"john\",\"age\":\"string instead of int\"}"; // when / then - waitAtMost(Duration.TEN_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { WebTestClient.ResponseSpec response = hermes.api().publish(topic.getQualifiedName(), message, createHeaders(Map.of("Content-Type", AVRO_JSON))); response.expectStatus().isBadRequest(); response.expectBody(String.class).isEqualTo( @@ -539,7 +539,7 @@ private void assertBodyDeserializesIntoUser(String body, AvroUser user) { } private void waitUntilSubscriptionContentTypeChanged(Topic topic, String subscription, ContentType expected) { - waitAtMost(adjust(Duration.TEN_SECONDS)).until(() -> { + waitAtMost(adjust(Duration.ofSeconds(10))).until(() -> { ContentType actual = hermes.api().getSubscription(topic.getQualifiedName(), subscription).getContentType(); logger.info("Expecting {} subscription endpoint address. Actual {}", expected, actual); return expected.equals(actual); @@ -548,7 +548,7 @@ private void waitUntilSubscriptionContentTypeChanged(Topic topic, String subscri private void waitUntilConsumerCommitsOffset(Topic topic, String subscription) { long currentTime = clock.millis(); - waitAtMost(adjust(Duration.ONE_MINUTE)).until(() -> + waitAtMost(adjust(Duration.ofMinutes(1))).until(() -> hermes.api().getRunningSubscriptionsStatus().stream() .filter(sub -> sub.getQualifiedName().equals(topic.getQualifiedName() + "$" + subscription)) .anyMatch(sub -> sub.getSignalTimesheet().getOrDefault(COMMIT, 0L) > currentTime)); @@ -556,7 +556,7 @@ private void waitUntilConsumerCommitsOffset(Topic topic, String subscription) { } private void waitUntilConsumersUpdateSubscription(final long currentTime, Topic topic, String subscription) { - waitAtMost(adjust(Duration.TEN_SECONDS)).until(() -> + waitAtMost(adjust(Duration.ofSeconds(10))).until(() -> hermes.api().getRunningSubscriptionsStatus().stream() .filter(sub -> sub.getQualifiedName().equals(topic.getQualifiedName() + "$" + subscription)) .anyMatch(sub -> sub.getSignalTimesheet().getOrDefault(UPDATE_SUBSCRIPTION, 0L) > currentTime)); diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingTest.java index e36db02694..54ab67272b 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/PublishingTest.java @@ -1,6 +1,6 @@ package pl.allegro.tech.hermes.integrationtests; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.http.HttpStatus; diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/ReadinessCheckTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/ReadinessCheckTest.java index bb3a914cea..e4f65f4b33 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/ReadinessCheckTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/ReadinessCheckTest.java @@ -1,11 +1,12 @@ package pl.allegro.tech.hermes.integrationtests; -import com.jayway.awaitility.Duration; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import pl.allegro.tech.hermes.integrationtests.setup.HermesExtension; -import static com.jayway.awaitility.Awaitility.waitAtMost; +import java.time.Duration; + +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.infrastructure.dc.DefaultDatacenterNameProvider.DEFAULT_DC_NAME; public class ReadinessCheckTest { @@ -19,7 +20,7 @@ public void shouldRespectReadinessStatusSetByAdmin() { hermes.api().setReadiness(DEFAULT_DC_NAME, false).expectStatus().isAccepted(); // then - waitAtMost(Duration.FIVE_SECONDS).until(() -> + waitAtMost(Duration.ofSeconds(5)).untilAsserted(() -> hermes.api() .getFrontendReadiness() .expectStatus().is5xxServerError() @@ -30,7 +31,7 @@ public void shouldRespectReadinessStatusSetByAdmin() { hermes.api().setReadiness(DEFAULT_DC_NAME, true).expectStatus().isAccepted(); // then - waitAtMost(Duration.FIVE_SECONDS).until(() -> + waitAtMost(Duration.ofSeconds(5)).untilAsserted(() -> hermes.api() .getFrontendReadiness() .expectStatus().isOk() diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/TopicAuthorizationTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/TopicAuthorizationTest.java index f394a94c8c..9f0fc17700 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/TopicAuthorizationTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/TopicAuthorizationTest.java @@ -1,7 +1,5 @@ package pl.allegro.tech.hermes.integrationtests; -import com.jayway.awaitility.Duration; -import org.apache.commons.codec.binary.Base64; import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -14,10 +12,12 @@ import pl.allegro.tech.hermes.utils.Headers; import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.Base64; import java.util.Map; import java.util.stream.Stream; -import static com.jayway.awaitility.Awaitility.waitAtMost; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.frontend.FrontendConfigurationProperties.AUTH_PASSWORD; import static pl.allegro.tech.hermes.frontend.FrontendConfigurationProperties.AUTH_USERNAME; import static pl.allegro.tech.hermes.frontend.FrontendConfigurationProperties.FRONTEND_AUTHENTICATION_ENABLED; @@ -46,7 +46,7 @@ public void shouldPublishWhenAuthenticated(Topic topic) { // given hermes.initHelper().createTopic(topic); - waitAtMost(Duration.TEN_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { // when WebTestClient.ResponseSpec response = hermes.api().publish( topic.getQualifiedName(), @@ -92,7 +92,7 @@ public void shouldPublishAsGuestWhenAuthIsNotRequired(Topic topic) { // given hermes.initHelper().createTopic(topic); - waitAtMost(Duration.TEN_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { // when WebTestClient.ResponseSpec response = hermes.api().publish(topic.getQualifiedName(), MESSAGE); @@ -121,7 +121,7 @@ public void shouldNotPublishAsGuestWhenAuthIsRequired(Topic topic) { // given hermes.initHelper().createTopic(topic); - waitAtMost(Duration.TEN_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { // when WebTestClient.ResponseSpec response = hermes.api().publish(topic.getQualifiedName(), MESSAGE); @@ -150,7 +150,7 @@ public void shouldNotPublishWithoutPermissionWhenAuthenticated(Topic topic) { // given hermes.initHelper().createTopic(topic); - waitAtMost(Duration.TEN_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { // when WebTestClient.ResponseSpec response = hermes.api().publish( topic.getQualifiedName(), @@ -187,7 +187,7 @@ static Stream notPublishWithoutPermissionWhenAuthenticatedTopics() { private static HttpHeaders createAuthorizationHeader(String username, String password) { String credentials = username + ":" + password; Map headers = Map.of( - "Authorization", "Basic " + Base64.encodeBase64String(credentials.getBytes(StandardCharsets.UTF_8)) + "Authorization", "Basic " + Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8)) ); return Headers.createHeaders(headers); } diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/TopicBlacklistTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/TopicBlacklistTest.java index 025ff765e3..3b98dd7d54 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/TopicBlacklistTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/TopicBlacklistTest.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.integrationtests; -import com.jayway.awaitility.Duration; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.test.web.reactive.server.WebTestClient; @@ -8,8 +7,10 @@ import pl.allegro.tech.hermes.integrationtests.setup.HermesExtension; import pl.allegro.tech.hermes.test.helper.message.TestMessage; -import static com.jayway.awaitility.Awaitility.waitAtMost; +import java.time.Duration; + import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.api.BlacklistStatus.BLACKLISTED; import static pl.allegro.tech.hermes.api.BlacklistStatus.NOT_BLACKLISTED; import static pl.allegro.tech.hermes.test.helper.builder.TopicBuilder.topicWithRandomName; @@ -27,7 +28,7 @@ public void shouldRefuseMessageOnBlacklistedTopic() { // when hermes.api().blacklistTopic(topic.getQualifiedName()); - waitAtMost(Duration.TEN_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { WebTestClient.ResponseSpec response = hermes.api().publish(topic.getQualifiedName(), message.body()); // then @@ -44,7 +45,7 @@ public void shouldAcceptMessageOnUnblacklistedTopic() { // when hermes.api().unblacklistTopic(topic.getQualifiedName()); - waitAtMost(Duration.TEN_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> { WebTestClient.ResponseSpec response = hermes.api().publish(topic.getQualifiedName(), message.body()); // then diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/UndeliveredLogTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/UndeliveredLogTest.java index 9c70941508..cd7b0e7341 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/UndeliveredLogTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/UndeliveredLogTest.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.integrationtests; -import com.jayway.awaitility.Duration; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import pl.allegro.tech.hermes.api.Subscription; @@ -8,7 +7,9 @@ import pl.allegro.tech.hermes.integrationtests.setup.HermesExtension; import pl.allegro.tech.hermes.test.helper.message.TestMessage; -import static com.jayway.awaitility.Awaitility.waitAtMost; +import java.time.Duration; + +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.test.helper.builder.SubscriptionBuilder.subscriptionWithRandomName; import static pl.allegro.tech.hermes.test.helper.builder.TopicBuilder.topicWithRandomName; @@ -29,7 +30,7 @@ public void shouldLogUndeliveredMessage() { hermes.api().publishUntilSuccess(topic.getQualifiedName(), TestMessage.simple().body()); // then - waitAtMost(Duration.TEN_SECONDS).until(() -> + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> hermes.api().getLatestUndeliveredMessage(topic.getQualifiedName(), subscription.getName()).expectStatus().is2xxSuccessful() ); } diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/GroupManagementTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/GroupManagementTest.java index 74ff23d653..b61e16cbef 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/GroupManagementTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/GroupManagementTest.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.integrationtests.management; -import com.jayway.awaitility.Duration; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -10,10 +9,11 @@ import pl.allegro.tech.hermes.integrationtests.setup.HermesExtension; import pl.allegro.tech.hermes.management.TestSecurityProvider; +import java.time.Duration; import java.util.stream.Stream; -import static com.jayway.awaitility.Awaitility.waitAtMost; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.api.ErrorCode.GROUP_NAME_IS_INVALID; import static pl.allegro.tech.hermes.api.ErrorCode.GROUP_NOT_EMPTY; import static pl.allegro.tech.hermes.integrationtests.management.TopicManagementTest.getErrorCode; @@ -111,8 +111,8 @@ public void shouldRemoveGroup() { // then response.expectStatus().isOk(); - waitAtMost(Duration.TEN_SECONDS) - .until(() -> Assertions.assertThat(hermes.api().getGroups()).doesNotContain(group.getGroupName())); + waitAtMost(Duration.ofSeconds(10)) + .untilAsserted(() -> Assertions.assertThat(hermes.api().getGroups()).doesNotContain(group.getGroupName())); } @Test @@ -127,8 +127,8 @@ public void shouldAllowNonAdminUserToRemoveGroup() { // then response.expectStatus().isOk(); - waitAtMost(Duration.TEN_SECONDS) - .until(() -> Assertions.assertThat(hermes.api().getGroups()).doesNotContain(group.getGroupName())); + waitAtMost(Duration.ofSeconds(10)) + .untilAsserted(() -> Assertions.assertThat(hermes.api().getGroups()).doesNotContain(group.getGroupName())); // cleanup TestSecurityProvider.reset(); diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/HealthCheckTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/HealthCheckTest.java index 0702d57d04..ca1447cbfa 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/HealthCheckTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/HealthCheckTest.java @@ -7,7 +7,7 @@ import java.util.concurrent.TimeUnit; -import static com.jayway.awaitility.Awaitility.await; +import static org.awaitility.Awaitility.await; public class HealthCheckTest { @@ -20,7 +20,7 @@ public void shouldManagementBeHealthy() { WebTestClient.ResponseSpec response = hermes.api().getManagementHealth(); // when & then - await().atMost(5, TimeUnit.SECONDS).until(() -> + await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> response.expectStatus().isOk()); } } diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/MessagePreviewIntegrationTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/MessagePreviewIntegrationTest.java index 1206a16e80..026de4a9fc 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/MessagePreviewIntegrationTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/MessagePreviewIntegrationTest.java @@ -9,12 +9,12 @@ import pl.allegro.tech.hermes.integrationtests.setup.HermesExtension; import pl.allegro.tech.hermes.test.helper.avro.AvroUser; +import java.time.Duration; import java.util.List; -import java.util.concurrent.TimeUnit; -import static com.jayway.awaitility.Awaitility.await; import static net.javacrumbs.jsonunit.fluent.JsonFluentAssert.assertThatJson; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import static pl.allegro.tech.hermes.api.ContentType.AVRO; import static pl.allegro.tech.hermes.api.TopicWithSchema.topicWithSchema; import static pl.allegro.tech.hermes.test.helper.builder.TopicBuilder.topicWithRandomName; @@ -37,7 +37,7 @@ public void shouldReturnAvroMessageWithSchemaAwareSerialization() { hermes.api().publishAvroUntilSuccess(topic.getQualifiedName(), avroUser.asBytes()); - await().atMost(10, TimeUnit.SECONDS).until(() -> { + await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> { // when List previews = hermes.api().getPreview(topic.getQualifiedName()) .expectStatus().isOk() diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/QueryEndpointTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/QueryEndpointTest.java index fb4bd6045a..12f9badb8b 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/QueryEndpointTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/QueryEndpointTest.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.integrationtests.management; -import com.jayway.awaitility.Duration; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; @@ -22,17 +21,18 @@ import pl.allegro.tech.hermes.test.helper.avro.AvroUserSchemaLoader; import pl.allegro.tech.hermes.test.helper.builder.SubscriptionBuilder; +import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.jayway.awaitility.Awaitility.waitAtMost; import static java.time.Duration.ofMinutes; import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; import static org.junit.jupiter.params.provider.Arguments.arguments; import static pl.allegro.tech.hermes.api.ContentType.AVRO; import static pl.allegro.tech.hermes.api.ContentType.JSON; @@ -442,7 +442,7 @@ public void shouldQueryTopicsMetrics(String topicName1, String topicName2, Strin .map(topicName -> group.getGroupName() + "." + topicName) .collect(toList()); - waitAtMost(adjust(Duration.ONE_MINUTE)).until(() -> { + waitAtMost(adjust(Duration.ofMinutes(1))).untilAsserted(() -> { // when List found = hermes.api().queryTopicMetrics(query) .expectStatus().isOk() @@ -486,7 +486,7 @@ public void shouldQuerySubscriptionsMetrics() { .build() ); - waitAtMost(adjust(Duration.ONE_MINUTE)).until(() -> { + waitAtMost(adjust(Duration.ofMinutes(1))).untilAsserted(() -> { // when final List allSubscriptions = hermes.api() .querySubscriptionMetrics(queryGetAllSubscriptionsMetrics) @@ -529,7 +529,7 @@ public void shouldHandleUnavailableSubscriptionsMetrics() { String queryGetSubscriptionsMetricsWithPositiveRate = "{\"query\": {\"rate\": {\"gt\": 0}}}"; prometheus.stubDelay(ofMinutes(10)); - waitAtMost(adjust(Duration.ONE_MINUTE)).until(() -> { + waitAtMost(adjust(Duration.ofMinutes(1))).untilAsserted(() -> { // when List allSubscriptions = hermes.api() .querySubscriptionMetrics(queryGetAllSubscriptionsMetrics) diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/SubscriptionManagementTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/SubscriptionManagementTest.java index 0f79a77283..7e9da9c1bf 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/SubscriptionManagementTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/SubscriptionManagementTest.java @@ -1,7 +1,6 @@ package pl.allegro.tech.hermes.integrationtests.management; import com.google.common.collect.ImmutableMap; -import com.jayway.awaitility.Duration; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; @@ -28,14 +27,15 @@ import pl.allegro.tech.hermes.management.TestSecurityProvider; import pl.allegro.tech.hermes.test.helper.message.TestMessage; +import java.time.Duration; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Stream; -import static com.jayway.awaitility.Awaitility.waitAtMost; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.api.PatchData.patchData; import static pl.allegro.tech.hermes.api.SubscriptionHealth.Status.NO_DATA; import static pl.allegro.tech.hermes.api.SubscriptionHealth.Status.UNHEALTHY; @@ -200,7 +200,7 @@ public void shouldUpdateSubscriptionEndpoint() { // then response.expectStatus().isOk(); - waitAtMost(Duration.TEN_SECONDS) + waitAtMost(Duration.ofSeconds(10)) .until(() -> hermes.api().getSubscriptionResponse(topic.getQualifiedName(), subscription.getName()) .expectStatus() .is2xxSuccessful() @@ -705,13 +705,13 @@ public void shouldMoveOffsetsToTheEnd() { hermes.api().deleteSubscription(topic.getQualifiedName(), subscription.getName()); // when - waitAtMost(Duration.TEN_SECONDS) - .until(() -> hermes.api() + waitAtMost(Duration.ofSeconds(10)) + .untilAsserted(() -> hermes.api() .moveOffsetsToTheEnd(topic.getQualifiedName(), subscription.getName()).expectStatus().isOk()); // then - waitAtMost(Duration.TEN_SECONDS) - .until(() -> assertThat(allConsumerGroupOffsetsMovedToTheEnd(subscription)).isTrue()); + waitAtMost(Duration.ofSeconds(10)) + .untilAsserted(() -> assertThat(allConsumerGroupOffsetsMovedToTheEnd(subscription)).isTrue()); } private boolean allConsumerGroupOffsetsMovedToTheEnd(Subscription subscription) { diff --git a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/TopicManagementTest.java b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/TopicManagementTest.java index f23c76d5df..d097604b40 100644 --- a/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/TopicManagementTest.java +++ b/integration-tests/src/integrationTest/java/pl/allegro/tech/hermes/integrationtests/management/TopicManagementTest.java @@ -2,7 +2,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.jayway.awaitility.Duration; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -22,6 +21,7 @@ import pl.allegro.tech.hermes.management.TestSecurityProvider; import pl.allegro.tech.hermes.test.helper.avro.AvroUserSchemaLoader; +import java.time.Duration; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -29,8 +29,8 @@ import java.util.Set; import java.util.stream.Stream; -import static com.jayway.awaitility.Awaitility.waitAtMost; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.api.ContentType.AVRO; import static pl.allegro.tech.hermes.api.ContentType.JSON; import static pl.allegro.tech.hermes.api.PatchData.patchData; @@ -143,7 +143,7 @@ public void shouldRemoveTopic() { // then response.expectStatus().isOk(); - waitAtMost(Duration.TEN_SECONDS).until(() -> assertThat(getGroupTopicsList(topic.getName().getGroupName())).isEmpty()); + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> assertThat(getGroupTopicsList(topic.getName().getGroupName())).isEmpty()); } @Test @@ -157,7 +157,7 @@ public void shouldUnblacklistTopicWhileDeleting() { // then response.expectStatus().isOk(); - waitAtMost(Duration.TEN_SECONDS).until(() -> assertThat(getGroupTopicsList(topic.getName().getGroupName())).isEmpty()); + waitAtMost(Duration.ofSeconds(10)).untilAsserted(() -> assertThat(getGroupTopicsList(topic.getName().getGroupName())).isEmpty()); assertThat(hermes.api().isTopicBlacklisted(topic.getQualifiedName()).isBlacklisted()).isFalse(); } diff --git a/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/BrokerLatencyReportingTest.java b/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/BrokerLatencyReportingTest.java index fed2d0e62f..e53cf88ea7 100644 --- a/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/BrokerLatencyReportingTest.java +++ b/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/BrokerLatencyReportingTest.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.integrationtests; -import com.jayway.awaitility.Duration; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Order; @@ -14,7 +13,9 @@ import pl.allegro.tech.hermes.test.helper.client.integration.FrontendTestClient; import pl.allegro.tech.hermes.test.helper.message.TestMessage; -import static com.jayway.awaitility.Awaitility.waitAtMost; +import java.time.Duration; + +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.integrationtests.assertions.HermesAssertions.assertThatMetrics; import static pl.allegro.tech.hermes.test.helper.builder.TopicBuilder.topicWithRandomName; @@ -56,7 +57,7 @@ public void shouldReportBrokerLatencyMetrics() { frontendTestClient.publishUntilSuccess(topic.getQualifiedName(), message.body()); // then - waitAtMost(Duration.FIVE_SECONDS).until(() -> { + waitAtMost(Duration.ofSeconds(5)).untilAsserted(() -> { frontendTestClient.getMetrics() .expectStatus() .isOk() diff --git a/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/HermesClientPublishingHttpsTest.java b/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/HermesClientPublishingHttpsTest.java index 45a05999af..35bacd5d11 100644 --- a/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/HermesClientPublishingHttpsTest.java +++ b/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/HermesClientPublishingHttpsTest.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.integrationtests; -import com.jayway.awaitility.Duration; import okhttp3.OkHttpClient; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -22,6 +21,7 @@ import pl.allegro.tech.hermes.test.helper.message.TestMessage; import java.net.URI; +import java.time.Duration; import javax.net.ssl.X509TrustManager; import static org.assertj.core.api.Assertions.assertThat; @@ -71,7 +71,7 @@ public void shouldCommunicateWithHermesUsingHttp2() { OkHttpHermesSender okHttpHermesSender = new OkHttpHermesSender(getOkHttpClientWithSslContextConfigured()); HermesClient client = hermesClient(okHttpHermesSender) .withRetries(5) - .withRetrySleep(Duration.FIVE_SECONDS.getValueInMS(), Duration.TEN_SECONDS.getValueInMS()) + .withRetrySleep(Duration.ofSeconds(5).toMillis(), Duration.ofSeconds(10).toMillis()) .withURI(URI.create("https://localhost:" + frontend.getSSLPort())) .build(); diff --git a/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/KafkaReadinessCheckTest.java b/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/KafkaReadinessCheckTest.java index 14eb1feeda..25873bdf84 100644 --- a/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/KafkaReadinessCheckTest.java +++ b/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/KafkaReadinessCheckTest.java @@ -20,8 +20,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.jayway.awaitility.Awaitility.await; import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; import static org.springframework.http.HttpStatus.SERVICE_UNAVAILABLE; import static pl.allegro.tech.hermes.api.Topic.Ack.ALL; import static pl.allegro.tech.hermes.integrationtests.assertions.HermesAssertions.assertThat; @@ -77,7 +77,7 @@ public void shouldNotBeReadyUntilKafkaClusterIsUp() { // then await().atMost(5, SECONDS) - .until(() -> getStatusReady(hermesFrontend).expectStatus().is2xxSuccessful()); + .untilAsserted(() -> getStatusReady(hermesFrontend).expectStatus().is2xxSuccessful()); getStatusHealth(hermesFrontend).expectStatus().is2xxSuccessful(); // cleanup @@ -129,7 +129,7 @@ public void shouldNotBeReadyUntilThereAreNoUnderReplicatedPartitions() throws Ex // then await().atMost(5, SECONDS) - .until(() -> getStatusReady(hermesFrontend).expectStatus().is2xxSuccessful()); + .untilAsserted(() -> getStatusReady(hermesFrontend).expectStatus().is2xxSuccessful()); getStatusHealth(hermesFrontend).expectStatus().is2xxSuccessful(); // cleanup @@ -173,7 +173,7 @@ public void shouldNotBeReadyUntilThereAreNoOfflinePartitions() throws Exception // then await().atMost(5, SECONDS) - .until(() -> getStatusReady(hermesFrontend).expectStatus().is2xxSuccessful()); + .untilAsserted(() -> getStatusReady(hermesFrontend).expectStatus().is2xxSuccessful()); getStatusHealth(hermesFrontend).expectStatus().is2xxSuccessful(); // cleanup diff --git a/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/MessageBufferLoadingTest.java b/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/MessageBufferLoadingTest.java index bc1bb936b5..7d679f80dc 100644 --- a/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/MessageBufferLoadingTest.java +++ b/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/MessageBufferLoadingTest.java @@ -27,12 +27,12 @@ import java.time.Clock; import java.util.Collections; -import static com.jayway.awaitility.Awaitility.await; import static jakarta.ws.rs.core.Response.Status.ACCEPTED; import static java.nio.charset.Charset.defaultCharset; import static java.time.Instant.now; import static java.util.concurrent.TimeUnit.SECONDS; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import static pl.allegro.tech.hermes.api.ContentType.JSON; import static pl.allegro.tech.hermes.frontend.FrontendConfigurationProperties.MESSAGES_LOCAL_STORAGE_DIRECTORY; import static pl.allegro.tech.hermes.frontend.FrontendConfigurationProperties.MESSAGES_LOCAL_STORAGE_ENABLED; @@ -92,7 +92,7 @@ public void shouldBackupMessage() { publisher.publishUntilStatus(topic.getQualifiedName(), "message", ACCEPTED.getStatusCode()); // then - await().atMost(10, SECONDS).until(() -> assertThat(backupRepository.findAll()).hasSize(1)); + await().atMost(10, SECONDS).untilAsserted(() -> assertThat(backupRepository.findAll()).hasSize(1)); } finally { // after diff --git a/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/TopicCreationRollbackTest.java b/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/TopicCreationRollbackTest.java index b74ff26aac..ab8f26c935 100644 --- a/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/TopicCreationRollbackTest.java +++ b/integration-tests/src/slowIntegrationTest/java/pl/allegro/tech/hermes/integrationtests/TopicCreationRollbackTest.java @@ -1,6 +1,5 @@ package pl.allegro.tech.hermes.integrationtests; -import com.jayway.awaitility.Duration; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -13,11 +12,12 @@ import pl.allegro.tech.hermes.test.helper.containers.KafkaContainerCluster; import pl.allegro.tech.hermes.test.helper.containers.ZookeeperContainer; +import java.time.Duration; import java.util.Map; import java.util.stream.Stream; -import static com.jayway.awaitility.Awaitility.waitAtMost; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; import static pl.allegro.tech.hermes.api.TopicWithSchema.topicWithSchema; import static pl.allegro.tech.hermes.infrastructure.dc.DefaultDatacenterNameProvider.DEFAULT_DC_NAME; import static pl.allegro.tech.hermes.test.helper.builder.TopicBuilder.topic; @@ -72,7 +72,7 @@ public void topicCreationRollbackShouldNotDeleteTopicOnBroker() { hermesApi.createGroup(Group.from(groupName)); brokerOperations1.createTopic(qualifiedTopicName); - waitAtMost(Duration.ONE_MINUTE).until(() -> assertThat(brokerOperations1.topicExists(qualifiedTopicName)).isTrue()); + waitAtMost(Duration.ofMinutes(1)).untilAsserted(() -> assertThat(brokerOperations1.topicExists(qualifiedTopicName)).isTrue()); // when hermesApi.createTopic((topicWithSchema(topic(groupName, topicName).build())));