From f53d0363cf6b75c8fc5167dbf9b5fd79b63602fc Mon Sep 17 00:00:00 2001 From: Sergii Chernysh Date: Tue, 17 Nov 2020 16:49:22 +0200 Subject: [PATCH] Add metrics to track settings cache population if it is enabled --- docs/metrics.md | 2 + .../org/prebid/server/metric/MetricName.java | 8 +- .../org/prebid/server/metric/Metrics.java | 16 +++ .../server/metric/SettingsCacheMetrics.java | 58 +++++++++++ .../service/JdbcPeriodicRefreshService.java | 99 ++++++++++++------- .../spring/config/SettingsConfiguration.java | 42 ++++++-- .../org/prebid/server/metric/MetricsTest.java | 22 +++++ .../JdbcPeriodicRefreshServiceTest.java | 96 ++++++++++-------- 8 files changed, 260 insertions(+), 83 deletions(-) create mode 100644 src/main/java/org/prebid/server/metric/SettingsCacheMetrics.java diff --git a/docs/metrics.md b/docs/metrics.md index 51521670249..f54a2291ae4 100644 --- a/docs/metrics.md +++ b/docs/metrics.md @@ -63,6 +63,8 @@ where `[DATASOURCE]` is a data source name, `DEFAULT_DS` by defaul. - `circuit-breaker.geo.opened` - state of the geo location circuit breaker: `1` means opened (geo location resource is unavailable), `0` - closed - `timeout_notification.ok` - number of times bidders were successfully notified about timeouts - `timeout_notification.failed` - number of unsuccessful attempts to notify bidders about timeouts +- `settings.cache.(stored-request|amp-stored-request).refresh.(initialize|update).db_query_time` - timer tracking how long was settings cache population +- `settings.cache.(stored-request|amp-stored-request).refresh.(initialize|update).err` - number of errors during settings cache population ## Auction per-adapter metrics - `adapter..no_cookie_requests` - number of requests made to `` that did not contain UID diff --git a/src/main/java/org/prebid/server/metric/MetricName.java b/src/main/java/org/prebid/server/metric/MetricName.java index 0418dbde191..e6e1a41871c 100644 --- a/src/main/java/org/prebid/server/metric/MetricName.java +++ b/src/main/java/org/prebid/server/metric/MetricName.java @@ -101,7 +101,13 @@ public enum MetricName { creative_size, //account.*.requests. - rejected; + rejected, + + // settings cache + stored_request("stored-request"), + amp_stored_request("amp-stored-request"), + initialize, + update; private final String name; diff --git a/src/main/java/org/prebid/server/metric/Metrics.java b/src/main/java/org/prebid/server/metric/Metrics.java index 05d333fc31e..c70c3a67869 100644 --- a/src/main/java/org/prebid/server/metric/Metrics.java +++ b/src/main/java/org/prebid/server/metric/Metrics.java @@ -32,6 +32,7 @@ public class Metrics extends UpdatableMetrics { private final Function adapterMetricsCreator; private final Function bidderCardinalityMetricsCreator; private final Function circuitBreakerMetricsCreator; + private final Function settingsCacheMetricsCreator; // not thread-safe maps are intentionally used here because it's harmless in this particular case - eventually // this all boils down to metrics lookup by underlying metric registry and that operation is guaranteed to be // thread-safe @@ -45,6 +46,7 @@ public class Metrics extends UpdatableMetrics { private final Map circuitBreakerMetrics; private final CacheMetrics cacheMetrics; private final TimeoutNotificationMetrics timeoutNotificationMetrics; + private final Map settingsCacheMetrics; public Metrics(MetricRegistry metricRegistry, CounterType counterType, AccountMetricsVerbosity accountMetricsVerbosity, BidderCatalog bidderCatalog) { @@ -59,6 +61,7 @@ public Metrics(MetricRegistry metricRegistry, CounterType counterType, AccountMe bidderCardinalityMetricsCreator = cardinality -> new BidderCardinalityMetrics( metricRegistry, counterType, cardinality); circuitBreakerMetricsCreator = type -> new CircuitBreakerMetrics(metricRegistry, counterType, type); + settingsCacheMetricsCreator = type -> new SettingsCacheMetrics(metricRegistry, counterType, type); requestMetrics = new EnumMap<>(MetricName.class); accountMetrics = new HashMap<>(); adapterMetrics = new HashMap<>(); @@ -69,6 +72,7 @@ public Metrics(MetricRegistry metricRegistry, CounterType counterType, AccountMe circuitBreakerMetrics = new HashMap<>(); cacheMetrics = new CacheMetrics(metricRegistry, counterType); timeoutNotificationMetrics = new TimeoutNotificationMetrics(metricRegistry, counterType); + settingsCacheMetrics = new HashMap<>(); } RequestStatusMetrics forRequestType(MetricName requestType) { @@ -107,6 +111,10 @@ CacheMetrics cache() { return cacheMetrics; } + SettingsCacheMetrics forSettingsCacheType(MetricName type) { + return settingsCacheMetrics.computeIfAbsent(type, settingsCacheMetricsCreator); + } + public void updateSafariRequestsMetric(boolean isSafari) { if (isSafari) { incCounter(MetricName.safari_requests); @@ -454,6 +462,14 @@ public void updateTimeoutNotificationMetric(boolean success) { } } + public void updateSettingsCacheRefreshTime(MetricName cacheType, MetricName refreshType, long timeElapsed) { + forSettingsCacheType(cacheType).forRefreshType(refreshType).updateTimer(MetricName.db_query_time, timeElapsed); + } + + public void updateSettingsCacheRefreshErrorMetric(MetricName cacheType, MetricName refreshType) { + forSettingsCacheType(cacheType).forRefreshType(refreshType).incCounter(MetricName.err); + } + private String resolveMetricsBidderName(String bidder) { return bidderCatalog.isValidName(bidder) ? bidder : METRICS_UNKNOWN_BIDDER; } diff --git a/src/main/java/org/prebid/server/metric/SettingsCacheMetrics.java b/src/main/java/org/prebid/server/metric/SettingsCacheMetrics.java new file mode 100644 index 00000000000..a78bf2223d0 --- /dev/null +++ b/src/main/java/org/prebid/server/metric/SettingsCacheMetrics.java @@ -0,0 +1,58 @@ +package org.prebid.server.metric; + +import com.codahale.metrics.MetricRegistry; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; + +/** + * Settings cache metrics support. + */ +class SettingsCacheMetrics extends UpdatableMetrics { + + private final Function refreshSettingsCacheMetricsCreator; + private final Map refreshSettingsCacheMetrics; + + SettingsCacheMetrics(MetricRegistry metricRegistry, CounterType counterType, MetricName type) { + super(Objects.requireNonNull(metricRegistry), Objects.requireNonNull(counterType), + nameCreator(createPrefix(Objects.requireNonNull(type)))); + + refreshSettingsCacheMetricsCreator = refreshType -> + new RefreshSettingsCacheMetrics(metricRegistry, counterType, createPrefix(type), refreshType); + refreshSettingsCacheMetrics = new HashMap<>(); + } + + RefreshSettingsCacheMetrics forRefreshType(MetricName refreshType) { + return refreshSettingsCacheMetrics.computeIfAbsent(refreshType, refreshSettingsCacheMetricsCreator); + } + + private static String createPrefix(MetricName type) { + return String.format("settings.cache.%s", type.toString()); + } + + private static Function nameCreator(String prefix) { + return metricName -> String.format("%s.%s", prefix, metricName.toString()); + } + + static class RefreshSettingsCacheMetrics extends UpdatableMetrics { + + RefreshSettingsCacheMetrics(MetricRegistry metricRegistry, + CounterType counterType, + String prefix, + MetricName type) { + + super(Objects.requireNonNull(metricRegistry), Objects.requireNonNull(counterType), + nameCreator(createPrefix(Objects.requireNonNull(prefix), Objects.requireNonNull(type)))); + } + + private static String createPrefix(String prefix, MetricName type) { + return String.format("%s.refresh.%s", prefix, type.toString()); + } + + private static Function nameCreator(String prefix) { + return metricName -> String.format("%s.%s", prefix, metricName.toString()); + } + } +} diff --git a/src/main/java/org/prebid/server/settings/service/JdbcPeriodicRefreshService.java b/src/main/java/org/prebid/server/settings/service/JdbcPeriodicRefreshService.java index 3be91567235..035a03fa028 100644 --- a/src/main/java/org/prebid/server/settings/service/JdbcPeriodicRefreshService.java +++ b/src/main/java/org/prebid/server/settings/service/JdbcPeriodicRefreshService.java @@ -7,12 +7,15 @@ import org.apache.commons.lang3.StringUtils; import org.prebid.server.execution.Timeout; import org.prebid.server.execution.TimeoutFactory; +import org.prebid.server.metric.MetricName; +import org.prebid.server.metric.Metrics; import org.prebid.server.settings.CacheNotificationListener; import org.prebid.server.settings.helper.JdbcStoredDataResultMapper; import org.prebid.server.settings.model.StoredDataResult; import org.prebid.server.vertx.Initializable; import org.prebid.server.vertx.jdbc.JdbcClient; +import java.time.Clock; import java.time.Instant; import java.util.Collections; import java.util.Date; @@ -42,11 +45,6 @@ public class JdbcPeriodicRefreshService implements Initializable { private static final Logger logger = LoggerFactory.getLogger(JdbcPeriodicRefreshService.class); - private final CacheNotificationListener cacheNotificationListener; - private final Vertx vertx; - private final JdbcClient jdbcClient; - private final long refreshPeriod; - /** * Example of initialize query: *
@@ -56,9 +54,8 @@ public class JdbcPeriodicRefreshService implements Initializable {
      * This query will be run once on startup to fetch _all_ known Stored Request data from the database.
      */
     private final String initQuery;
-
     /**
-     * Example of initialize query:
+     * Example of update query:
      * 
      * SELECT id, requestData, type
      * FROM stored_requests
@@ -68,21 +65,41 @@ public class JdbcPeriodicRefreshService implements Initializable {
      * Wildcard "?" would be used to pass last update date automatically.
      */
     private final String updateQuery;
-    private final TimeoutFactory timeoutFactory;
+    private final long refreshPeriod;
     private final long timeout;
+    private final MetricName cacheType;
+    private final CacheNotificationListener cacheNotificationListener;
+    private final Vertx vertx;
+    private final JdbcClient jdbcClient;
+    private final TimeoutFactory timeoutFactory;
+    private final Metrics metrics;
+    private final Clock clock;
+
     private Instant lastUpdate;
 
-    public JdbcPeriodicRefreshService(CacheNotificationListener cacheNotificationListener,
-                                      Vertx vertx, JdbcClient jdbcClient, long refreshPeriod, String initQuery,
-                                      String updateQuery, TimeoutFactory timeoutFactory, long timeout) {
+    public JdbcPeriodicRefreshService(String initQuery,
+                                      String updateQuery,
+                                      long refreshPeriod,
+                                      long timeout,
+                                      MetricName cacheType,
+                                      CacheNotificationListener cacheNotificationListener,
+                                      Vertx vertx,
+                                      JdbcClient jdbcClient,
+                                      TimeoutFactory timeoutFactory,
+                                      Metrics metrics,
+                                      Clock clock) {
+
+        this.initQuery = Objects.requireNonNull(StringUtils.stripToNull(initQuery));
+        this.updateQuery = Objects.requireNonNull(StringUtils.stripToNull(updateQuery));
+        this.refreshPeriod = refreshPeriod;
+        this.timeout = timeout;
+        this.cacheType = Objects.requireNonNull(cacheType);
         this.cacheNotificationListener = Objects.requireNonNull(cacheNotificationListener);
         this.vertx = Objects.requireNonNull(vertx);
         this.jdbcClient = Objects.requireNonNull(jdbcClient);
-        this.refreshPeriod = refreshPeriod;
-        this.initQuery = Objects.requireNonNull(StringUtils.stripToNull(initQuery));
-        this.updateQuery = Objects.requireNonNull(StringUtils.stripToNull(updateQuery));
         this.timeoutFactory = Objects.requireNonNull(timeoutFactory);
-        this.timeout = timeout;
+        this.metrics = Objects.requireNonNull(metrics);
+        this.clock = Objects.requireNonNull(clock);
     }
 
     @Override
@@ -94,36 +111,52 @@ public void initialize() {
     }
 
     private void getAll() {
-        jdbcClient.executeQuery(initQuery, Collections.emptyList(), JdbcStoredDataResultMapper::map, createTimeout())
-                .map(this::save)
-                .map(ignored -> setLastUpdate(Instant.now()))
-                .recover(JdbcPeriodicRefreshService::failResponse);
+        final long startTime = clock.millis();
+
+        jdbcClient.executeQuery(
+                initQuery,
+                Collections.emptyList(),
+                JdbcStoredDataResultMapper::map,
+                createTimeout())
+                .map(storedDataResult ->
+                        handleResult(storedDataResult, Instant.now(clock), startTime, MetricName.initialize))
+                .recover(exception -> handleFailure(exception, startTime, MetricName.initialize));
     }
 
-    private Void save(StoredDataResult storedDataResult) {
+    private Void handleResult(StoredDataResult storedDataResult,
+                              Instant updateTime,
+                              long startTime,
+                              MetricName refreshType) {
+
         cacheNotificationListener.save(storedDataResult.getStoredIdToRequest(), storedDataResult.getStoredIdToImp());
-        return null;
-    }
+        lastUpdate = updateTime;
+
+        metrics.updateSettingsCacheRefreshTime(cacheType, refreshType, clock.millis() - startTime);
 
-    private Void setLastUpdate(Instant instant) {
-        lastUpdate = instant;
         return null;
     }
 
-    private static Future failResponse(Throwable exception) {
+    private Future handleFailure(Throwable exception, long startTime, MetricName refreshType) {
         logger.warn("Error occurred while request to jdbc refresh service", exception);
+
+        metrics.updateSettingsCacheRefreshTime(cacheType, refreshType, clock.millis() - startTime);
+        metrics.updateSettingsCacheRefreshErrorMetric(cacheType, refreshType);
+
         return Future.failedFuture(exception);
     }
 
     private void refresh() {
-        final Instant updateTime = Instant.now();
-
-        jdbcClient.executeQuery(updateQuery, Collections.singletonList(Date.from(lastUpdate)),
-                JdbcStoredDataResultMapper::map, createTimeout())
-                .map(this::invalidate)
-                .map(this::save)
-                .map(ignored -> setLastUpdate(updateTime))
-                .recover(JdbcPeriodicRefreshService::failResponse);
+        final Instant updateTime = Instant.now(clock);
+        final long startTime = clock.millis();
+
+        jdbcClient.executeQuery(
+                updateQuery,
+                Collections.singletonList(Date.from(lastUpdate)),
+                JdbcStoredDataResultMapper::map,
+                createTimeout())
+                .map(storedDataResult ->
+                        handleResult(invalidate(storedDataResult), updateTime, startTime, MetricName.update))
+                .recover(exception -> handleFailure(exception, startTime, MetricName.update));
     }
 
     private StoredDataResult invalidate(StoredDataResult storedDataResult) {
diff --git a/src/main/java/org/prebid/server/spring/config/SettingsConfiguration.java b/src/main/java/org/prebid/server/spring/config/SettingsConfiguration.java
index d4c80580f46..c3235db6691 100644
--- a/src/main/java/org/prebid/server/spring/config/SettingsConfiguration.java
+++ b/src/main/java/org/prebid/server/spring/config/SettingsConfiguration.java
@@ -10,6 +10,7 @@
 import org.apache.commons.lang3.ObjectUtils;
 import org.prebid.server.execution.TimeoutFactory;
 import org.prebid.server.json.JacksonMapper;
+import org.prebid.server.metric.MetricName;
 import org.prebid.server.metric.Metrics;
 import org.prebid.server.settings.ApplicationSettings;
 import org.prebid.server.settings.CachingApplicationSettings;
@@ -229,7 +230,8 @@ public HttpPeriodicRefreshService ampHttpPeriodicRefreshService(
     }
 
     @Configuration
-    @ConditionalOnProperty(prefix = "settings.in-memory-cache.jdbc-update",
+    @ConditionalOnProperty(
+            prefix = "settings.in-memory-cache.jdbc-update",
             name = {"refresh-rate", "timeout", "init-query", "update-query", "amp-init-query", "amp-update-query"})
     static class JdbcPeriodicRefreshServiceConfiguration {
 
@@ -248,24 +250,50 @@ static class JdbcPeriodicRefreshServiceConfiguration {
         @Autowired
         TimeoutFactory timeoutFactory;
 
+        @Autowired
+        Metrics metrics;
+
+        @Autowired
+        Clock clock;
+
         @Bean
         public JdbcPeriodicRefreshService jdbcPeriodicRefreshService(
-                SettingsCache settingsCache,
+                @Qualifier("settingsCache") SettingsCache settingsCache,
                 @Value("${settings.in-memory-cache.jdbc-update.init-query}") String initQuery,
                 @Value("${settings.in-memory-cache.jdbc-update.update-query}") String updateQuery) {
 
-            return new JdbcPeriodicRefreshService(settingsCache, vertx, jdbcClient, refreshPeriod,
-                    initQuery, updateQuery, timeoutFactory, timeout);
+            return new JdbcPeriodicRefreshService(
+                    initQuery,
+                    updateQuery,
+                    refreshPeriod,
+                    timeout,
+                    MetricName.stored_request,
+                    settingsCache,
+                    vertx,
+                    jdbcClient,
+                    timeoutFactory,
+                    metrics,
+                    clock);
         }
 
         @Bean
         public JdbcPeriodicRefreshService ampJdbcPeriodicRefreshService(
-                SettingsCache settingsCache,
+                @Qualifier("ampSettingsCache") SettingsCache ampSettingsCache,
                 @Value("${settings.in-memory-cache.jdbc-update.amp-init-query}") String ampInitQuery,
                 @Value("${settings.in-memory-cache.jdbc-update.amp-update-query}") String ampUpdateQuery) {
 
-            return new JdbcPeriodicRefreshService(settingsCache, vertx, jdbcClient, refreshPeriod,
-                    ampInitQuery, ampUpdateQuery, timeoutFactory, timeout);
+            return new JdbcPeriodicRefreshService(
+                    ampInitQuery,
+                    ampUpdateQuery,
+                    refreshPeriod,
+                    timeout,
+                    MetricName.amp_stored_request,
+                    ampSettingsCache,
+                    vertx,
+                    jdbcClient,
+                    timeoutFactory,
+                    metrics,
+                    clock);
         }
     }
 
diff --git a/src/test/java/org/prebid/server/metric/MetricsTest.java b/src/test/java/org/prebid/server/metric/MetricsTest.java
index 0ddffed3dc7..67e94eefe7d 100644
--- a/src/test/java/org/prebid/server/metric/MetricsTest.java
+++ b/src/test/java/org/prebid/server/metric/MetricsTest.java
@@ -987,6 +987,28 @@ public void shouldIncrementPrebidCacheCreativeSizeHistogram() {
                 .isEqualTo(1);
     }
 
+    @Test
+    public void updateSettingsCacheRefreshTimeShouldUpdateTimer() {
+        // when
+        metrics.updateSettingsCacheRefreshTime(MetricName.stored_request, MetricName.initialize, 123L);
+
+        // then
+        assertThat(metricRegistry
+                .timer("settings.cache.stored-request.refresh.initialize.db_query_time")
+                .getCount())
+                .isEqualTo(1);
+    }
+
+    @Test
+    public void updateSettingsCacheRefreshErrorMetricShouldIncrementMetric() {
+        // when
+        metrics.updateSettingsCacheRefreshErrorMetric(MetricName.stored_request, MetricName.initialize);
+
+        // then
+        assertThat(metricRegistry.counter("settings.cache.stored-request.refresh.initialize.err").getCount())
+                .isEqualTo(1);
+    }
+
     private void verifyCreatesConfiguredCounterType(Consumer metricsConsumer) {
         final EnumMap> counterTypeClasses = new EnumMap<>(CounterType.class);
         counterTypeClasses.put(CounterType.counter, Counter.class);
diff --git a/src/test/java/org/prebid/server/settings/service/JdbcPeriodicRefreshServiceTest.java b/src/test/java/org/prebid/server/settings/service/JdbcPeriodicRefreshServiceTest.java
index 2110ecd80a1..5e49e305238 100644
--- a/src/test/java/org/prebid/server/settings/service/JdbcPeriodicRefreshServiceTest.java
+++ b/src/test/java/org/prebid/server/settings/service/JdbcPeriodicRefreshServiceTest.java
@@ -11,6 +11,8 @@
 import org.mockito.junit.MockitoRule;
 import org.mockito.stubbing.Answer;
 import org.prebid.server.execution.TimeoutFactory;
+import org.prebid.server.metric.MetricName;
+import org.prebid.server.metric.Metrics;
 import org.prebid.server.settings.CacheNotificationListener;
 import org.prebid.server.settings.model.StoredDataResult;
 import org.prebid.server.vertx.jdbc.JdbcClient;
@@ -24,7 +26,6 @@
 import static java.util.Collections.emptyMap;
 import static java.util.Collections.singletonList;
 import static java.util.Collections.singletonMap;
-import static org.assertj.core.api.Assertions.assertThatNullPointerException;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -37,21 +38,22 @@
 
 public class JdbcPeriodicRefreshServiceTest {
 
-    private static TimeoutFactory timeoutFactory = new TimeoutFactory(
-            Clock.fixed(Instant.now(), ZoneId.systemDefault()));
-
     @Rule
     public final MockitoRule mockitoRule = MockitoJUnit.rule();
 
     @Mock
     private CacheNotificationListener cacheNotificationListener;
     @Mock
+    private Vertx vertx;
+    @Mock
     private JdbcClient jdbcClient;
+    private final Clock clock = Clock.fixed(Instant.now(), ZoneId.systemDefault());
+    private final TimeoutFactory timeoutFactory = new TimeoutFactory(clock);
     @Mock
-    private Vertx vertx;
+    private Metrics metrics;
 
-    private Map expectedRequests = singletonMap("id1", "value1");
-    private Map expectedImps = singletonMap("id2", "value2");
+    private final Map expectedRequests = singletonMap("id1", "value1");
+    private final Map expectedImps = singletonMap("id2", "value2");
 
     @Before
     public void setUp() {
@@ -66,31 +68,10 @@ public void setUp() {
                 .willReturn(Future.succeededFuture(updateResult));
     }
 
-    @Test
-    public void creationShouldFailOnNullArgumentsAndBlankQuery() {
-        assertThatNullPointerException().isThrownBy(() -> createAndInitService(
-                null, null, null, 0, null, null, null, 0));
-        assertThatNullPointerException().isThrownBy(() -> createAndInitService(
-                cacheNotificationListener, null, null, 0, null, null, null, 0));
-        assertThatNullPointerException().isThrownBy(() -> createAndInitService(
-                cacheNotificationListener, vertx, null, 0, null, null, null, 0));
-        assertThatNullPointerException().isThrownBy(() -> createAndInitService(
-                cacheNotificationListener, vertx, jdbcClient, 0, null, null, null, 0));
-        assertThatNullPointerException().isThrownBy(() -> createAndInitService(
-                cacheNotificationListener, vertx, jdbcClient, 0, "init_query", null, null, 0));
-        assertThatNullPointerException().isThrownBy(() -> createAndInitService(
-                cacheNotificationListener, vertx, jdbcClient, 0, "init_query", "update_query", null, 0));
-        assertThatNullPointerException().isThrownBy(() -> createAndInitService(
-                cacheNotificationListener, vertx, jdbcClient, 0, "  ", null, timeoutFactory, 0));
-        assertThatNullPointerException().isThrownBy(() -> createAndInitService(
-                cacheNotificationListener, vertx, jdbcClient, 0, "init_query", " ", timeoutFactory, 0));
-    }
-
     @Test
     public void shouldCallSaveWithExpectedParameters() {
         // when
-        createAndInitService(cacheNotificationListener, vertx, jdbcClient, 1000,
-                "init_query", "update_query", timeoutFactory, 2000);
+        createAndInitService(1000);
 
         // then
         verify(cacheNotificationListener).save(expectedRequests, expectedImps);
@@ -103,8 +84,7 @@ public void shouldCallInvalidateAndSaveWithExpectedParameters() {
                 .willAnswer(withSelfAndPassObjectToHandler(1L));
 
         // when
-        createAndInitService(cacheNotificationListener, vertx, jdbcClient, 1000,
-                "init_query", "update_query", timeoutFactory, 2000);
+        createAndInitService(1000);
 
         // then
         verify(cacheNotificationListener).save(expectedRequests, expectedImps);
@@ -119,8 +99,7 @@ public void initializeShouldMakeOneInitialRequestAndTwoScheduledRequestsWithPara
                 .willAnswer(withSelfAndPassObjectToHandler(1L, 2L));
 
         // when
-        createAndInitService(cacheNotificationListener, vertx, jdbcClient, 1000,
-                "init_query", "update_query", timeoutFactory, 2000);
+        createAndInitService(1000);
 
         // then
         verify(jdbcClient).executeQuery(eq("init_query"), eq(emptyList()), any(), any());
@@ -130,21 +109,54 @@ public void initializeShouldMakeOneInitialRequestAndTwoScheduledRequestsWithPara
     @Test
     public void initializeShouldMakeOnlyOneInitialRequestIfRefreshPeriodIsNegative() {
         // when
-        createAndInitService(cacheNotificationListener, vertx, jdbcClient, -1,
-                "init_query", "update_query", timeoutFactory, 2000);
+        createAndInitService(-1);
 
         // then
         verify(vertx, never()).setPeriodic(anyLong(), any());
         verify(jdbcClient).executeQuery(anyString(), anyList(), any(), any());
     }
 
-    private static void createAndInitService(CacheNotificationListener cacheNotificationListener,
-                                             Vertx vertx, JdbcClient jdbcClient, long refresh,
-                                             String query, String updateQuery,
-                                             TimeoutFactory timeoutFactory, long timeout) {
-        final JdbcPeriodicRefreshService jdbcPeriodicRefreshService =
-                new JdbcPeriodicRefreshService(cacheNotificationListener, vertx, jdbcClient, refresh,
-                        query, updateQuery, timeoutFactory, timeout);
+    @Test
+    public void shouldUpdateTimerMetric() {
+        // when
+        createAndInitService(1000);
+
+        // then
+        verify(metrics).updateSettingsCacheRefreshTime(
+                eq(MetricName.stored_request), eq(MetricName.initialize), anyLong());
+    }
+
+    @Test
+    public void shouldUpdateTimerAndErrorMetric() {
+        // given
+        given(jdbcClient.executeQuery(eq("init_query"), anyList(), any(), any()))
+                .willReturn(Future.failedFuture("Query error"));
+
+        // when
+        createAndInitService(1000);
+
+        // then
+        verify(metrics).updateSettingsCacheRefreshTime(
+                eq(MetricName.stored_request), eq(MetricName.initialize), anyLong());
+        verify(metrics).updateSettingsCacheRefreshErrorMetric(
+                eq(MetricName.stored_request), eq(MetricName.initialize));
+    }
+
+    private void createAndInitService(long refresh) {
+
+        final JdbcPeriodicRefreshService jdbcPeriodicRefreshService = new JdbcPeriodicRefreshService(
+                "init_query",
+                "update_query",
+                refresh,
+                2000,
+                MetricName.stored_request,
+                cacheNotificationListener,
+                vertx,
+                jdbcClient,
+                timeoutFactory,
+                metrics,
+                clock);
+
         jdbcPeriodicRefreshService.initialize();
     }