Repository: mageddo/dns-proxy-server (java)

Issue:
Add DNS caching time parameter for multiple servers
I would like to suggest adding the ability to configure the caching time parameter when multiple DNS servers are available. For example, in my configuration, I have two DNS servers: 10.0.0.10 and 8.8.8.8. The first DNS (10.0.0.10) is used via VPN, and if it does not respond, the request will be sent to the second DNS (8.8.8.8). Currently, all subsequent requests go to the second DNS. However, I would like the system to switch back to resolving requests from the first DNS after a specified time. 

Perhaps these 20 seconds should be made a configurable parameter:
https://github.com/mageddo/dns-proxy-server/blob/17b0c0043d883cf9f902075739183c7938c808b2/src/main/java/com/mageddo/dnsproxyserver/server/dns/solver/SolverRemote.java#L174
 
This change would allow for more flexible management of DNS request caching and ensure more efficient operation with multiple DNS servers. I would appreciate your consideration of this proposal. Thank you! 


Pull request:
Parameters for Remote Solver Circuit Breaker 
Implementing #440 

Patch:
diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index edcde94e..33cf4850 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -1,3 +1,6 @@
+## 3.18.0
+* Parameters for Remote Solver Circuit Breaker, see #440.
+
 ## 3.17.3
 * DPS Config module refactoring due #440, see #447 
 
diff --git a/build.gradle b/build.gradle
index 4af186a4..e2e4c70b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -50,6 +50,7 @@ dependencies {
   implementation('com.github.docker-java:docker-java-transport-httpclient5:3.3.4')
 
   implementation('info.picocli:picocli:4.7.1')
+  implementation('com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.1')
 
   testAnnotationProcessor("com.google.dagger:dagger-compiler:2.45")
   testCompileOnly('org.projectlombok:lombok:1.18.+')
@@ -59,6 +60,7 @@ dependencies {
   testImplementation('org.mockito:mockito-junit-jupiter:5.1.+')
   testImplementation('io.rest-assured:rest-assured:5.3.0')
 
+
 }
 
 test {
diff --git a/docs/content/1-getting-started/versioning.md b/docs/content/1-getting-started/versioning.md
index 1eebb61f..51fc387f 100644
--- a/docs/content/1-getting-started/versioning.md
+++ b/docs/content/1-getting-started/versioning.md
@@ -28,11 +28,11 @@ There are three types of docker images
 You can see every release note on the [releases download page][2] or at the [release notes.md][5] file
 
 ## Reference
-DPS release process was inpired on [Gradle][4] and Debian releasing process.
+DPS release process was inspired on [Gradle][4] and Debian releasing process.
 
 [1]: https://en.wikipedia.org/wiki/Software_versioning#Semantic_versioning
 [2]: https://github.com/mageddo/dns-proxy-server/releases
-[3]: https://hub.docker.com/r/defreitas/dns-proxy-server/t
+[3]: https://hub.docker.com/r/defreitas/dns-proxy-server/
 [4]: https://docs.gradle.org/7.6.1/release-notes.html
 [5]: https://github.com/mageddo/dns-proxy-server/blob/master/RELEASE-NOTES.md
 [6]: https://semver.org/
diff --git a/docs/content/3-configuration/_index.en.md b/docs/content/3-configuration/_index.en.md
index 45a53089..3d545f8c 100755
--- a/docs/content/3-configuration/_index.en.md
+++ b/docs/content/3-configuration/_index.en.md
@@ -167,7 +167,15 @@ __Version 2__
   "resolvConfOverrideNameServers": true,
   "noRemoteServers": false,
   "noEntriesResponseCode": 3,
-  "dockerSolverHostMachineFallbackActive": true
+  "dockerSolverHostMachineFallbackActive": true,
+  "solverRemote" : {
+    "circuitBreaker" : { 
+      "failureThreshold" : 3, // how many attempts before open the circuit?
+      "failureThresholdCapacity" : 10, // how many attempts store to the stack?
+      "successThreshold" : 5, // how many attempts before close the circuit?
+      "testDelay" : "PT1M" // how many time to wait before test the circuit again?
+    }
+  }
 }
 ```
 
diff --git a/gradle.properties b/gradle.properties
index 1733f357..c5c40ea0 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,1 +1,1 @@
-version=3.17.3-snapshot
+version=3.18.0-snapshot
diff --git a/src/main/java/com/mageddo/dnsproxyserver/config/CircuitBreaker.java b/src/main/java/com/mageddo/dnsproxyserver/config/CircuitBreaker.java
new file mode 100644
index 00000000..a54b4a43
--- /dev/null
+++ b/src/main/java/com/mageddo/dnsproxyserver/config/CircuitBreaker.java
@@ -0,0 +1,28 @@
+package com.mageddo.dnsproxyserver.config;
+
+import lombok.Builder;
+import lombok.Value;
+
+import java.time.Duration;
+
+
+@Value
+@Builder
+public class CircuitBreaker {
+
+  /**
+   * See {@link dev.failsafe.CircuitBreakerBuilder#withFailureThreshold(int, int)}
+   */
+  private Integer failureThreshold;
+  private Integer failureThresholdCapacity;
+
+  /**
+   * @see dev.failsafe.CircuitBreakerBuilder#withSuccessThreshold(int)
+   */
+  private Integer successThreshold;
+
+  /**
+   * @see dev.failsafe.CircuitBreakerBuilder#withDelay(Duration)
+   */
+  private Duration testDelay;
+}
diff --git a/src/main/java/com/mageddo/dnsproxyserver/config/Config.java b/src/main/java/com/mageddo/dnsproxyserver/config/Config.java
index 2e52d363..b61d4063 100644
--- a/src/main/java/com/mageddo/dnsproxyserver/config/Config.java
+++ b/src/main/java/com/mageddo/dnsproxyserver/config/Config.java
@@ -77,6 +77,8 @@ public class Config {
 
   private boolean versionCmd;
 
+  private SolverRemote solverRemote;
+
   public void resetConfigFile() {
     try {
       Files.deleteIfExists(this.getConfigPath());
diff --git a/src/main/java/com/mageddo/dnsproxyserver/config/SolverRemote.java b/src/main/java/com/mageddo/dnsproxyserver/config/SolverRemote.java
new file mode 100644
index 00000000..78340bcf
--- /dev/null
+++ b/src/main/java/com/mageddo/dnsproxyserver/config/SolverRemote.java
@@ -0,0 +1,12 @@
+package com.mageddo.dnsproxyserver.config;
+
+import lombok.Builder;
+import lombok.NonNull;
+import lombok.Value;
+
+@Value
+@Builder
+public class SolverRemote {
+  @NonNull
+  private CircuitBreaker circuitBreaker;
+}
diff --git a/src/main/java/com/mageddo/dnsproxyserver/config/application/Configs.java b/src/main/java/com/mageddo/dnsproxyserver/config/application/Configs.java
index 063cf746..a83a25f5 100644
--- a/src/main/java/com/mageddo/dnsproxyserver/config/application/Configs.java
+++ b/src/main/java/com/mageddo/dnsproxyserver/config/application/Configs.java
@@ -2,7 +2,7 @@ package com.mageddo.dnsproxyserver.config.application;
 
 import com.mageddo.commons.lang.Singletons;
 import com.mageddo.dnsproxyserver.config.Config;
-import com.mageddo.dnsproxyserver.config.configurator.Context;
+import com.mageddo.dnsproxyserver.config.di.Context;
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
diff --git a/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/ConfigDAOJson.java b/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/ConfigDAOJson.java
index 3d83ca35..2c377e0f 100644
--- a/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/ConfigDAOJson.java
+++ b/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/ConfigDAOJson.java
@@ -1,6 +1,8 @@
 package com.mageddo.dnsproxyserver.config.dataprovider;
 
+import com.mageddo.dnsproxyserver.config.CircuitBreaker;
 import com.mageddo.dnsproxyserver.config.Config;
+import com.mageddo.dnsproxyserver.config.SolverRemote;
 import com.mageddo.dnsproxyserver.config.dataprovider.mapper.ConfigFieldsValuesMapper;
 import com.mageddo.dnsproxyserver.config.dataprovider.vo.ConfigJson;
 import com.mageddo.utils.Files;
@@ -28,9 +30,13 @@ public class ConfigDAOJson implements ConfigDAO {
     final var workDir = this.configDAOEnv.findRaw().getCurrentPath();
     final var relativeConfigFilePath = this.configDAOCmdArgs.findRaw().getConfigPath();
     final var configFileAbsolutePath = buildConfigPath(workDir, relativeConfigFilePath);
-    final var jsonConfig = JsonConfigs.loadConfig(configFileAbsolutePath);
-    log.info("status=configuring, configFile={}", configFileAbsolutePath);
-    return toConfig(jsonConfig, configFileAbsolutePath);
+    return this.find(configFileAbsolutePath);
+  }
+
+  public Config find(Path configPath) {
+    final var jsonConfig = JsonConfigs.loadConfig(configPath);
+    log.info("status=configuring, configPath={}", configPath);
+    return toConfig(jsonConfig, configPath);
   }
 
   public static Path buildConfigPath(Path workDir, String configPath) {
@@ -78,6 +84,29 @@ public class ConfigDAOJson implements ConfigDAO {
       .noEntriesResponseCode(json.getNoEntriesResponseCode())
       .dockerSolverHostMachineFallbackActive(json.getDockerSolverHostMachineFallbackActive())
       .configPath(configFileAbsolutePath)
+      .solverRemote(toSolverRemote(json))
+      .build();
+  }
+
+  static SolverRemote toSolverRemote(ConfigJson json) {
+    final var solverRemote = json.getSolverRemote();
+    if (solverRemote == null) {
+      return null;
+    }
+    final var circuitBreaker = solverRemote.getCircuitBreaker();
+    if (circuitBreaker == null) {
+      return null;
+    }
+    return SolverRemote
+      .builder()
+      .circuitBreaker(CircuitBreaker
+        .builder()
+        .failureThreshold(circuitBreaker.getFailureThreshold())
+        .failureThresholdCapacity(circuitBreaker.getFailureThresholdCapacity())
+        .successThreshold(circuitBreaker.getSuccessThreshold())
+        .testDelay(circuitBreaker.getTestDelay())
+        .build()
+      )
       .build();
   }
 
diff --git a/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/PersistentConfigDAOJson.java b/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/PersistentConfigDAOJson.java
index e1e3b48a..d582dec4 100644
--- a/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/PersistentConfigDAOJson.java
+++ b/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/PersistentConfigDAOJson.java
@@ -2,11 +2,11 @@ package com.mageddo.dnsproxyserver.config.dataprovider;
 
 import com.mageddo.dnsproxyserver.config.Config;
 import com.mageddo.dnsproxyserver.config.application.Configs;
-import com.mageddo.dnsproxyserver.config.dataprovider.vo.ConfigJson;
-import com.mageddo.dnsproxyserver.config.dataprovider.vo.ConfigJsonV2;
-import com.mageddo.dnsproxyserver.config.dataprovider.predicate.JsonEnvPredicate;
 import com.mageddo.dnsproxyserver.config.dataprovider.predicate.EntryPredicate;
 import com.mageddo.dnsproxyserver.config.dataprovider.predicate.EnvPredicate;
+import com.mageddo.dnsproxyserver.config.dataprovider.predicate.JsonEnvPredicate;
+import com.mageddo.dnsproxyserver.config.dataprovider.vo.ConfigJson;
+import com.mageddo.dnsproxyserver.config.dataprovider.vo.ConfigJsonV2;
 import com.mageddo.dnsproxyserver.server.dns.solver.HostnameQuery;
 import lombok.NoArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
diff --git a/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/vo/ConfigJson.java b/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/vo/ConfigJson.java
index dc6f65b2..02fb9520 100644
--- a/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/vo/ConfigJson.java
+++ b/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/vo/ConfigJson.java
@@ -1,8 +1,8 @@
 package com.mageddo.dnsproxyserver.config.dataprovider.vo;
 
 import com.mageddo.dnsproxyserver.config.Config;
-import com.mageddo.net.IpAddr;
 import com.mageddo.dnsproxyserver.server.dns.SimpleServer;
+import com.mageddo.net.IpAddr;
 
 import java.net.URI;
 import java.util.List;
@@ -46,4 +46,7 @@ public interface ConfigJson {
   Integer getNoEntriesResponseCode();
 
   Boolean getDockerSolverHostMachineFallbackActive();
+
+  ConfigJsonV2.SolverRemote getSolverRemote();
+
 }
diff --git a/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/vo/ConfigJsonV1.java b/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/vo/ConfigJsonV1.java
index 8315bda9..75412752 100644
--- a/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/vo/ConfigJsonV1.java
+++ b/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/vo/ConfigJsonV1.java
@@ -4,8 +4,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.mageddo.dnsproxyserver.config.Config;
 import com.mageddo.dnsproxyserver.config.dataprovider.mapper.ConfigJsonV1EnvsMapper;
-import com.mageddo.net.IpAddr;
 import com.mageddo.dnsproxyserver.server.dns.SimpleServer;
+import com.mageddo.net.IpAddr;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.NonNull;
@@ -108,6 +108,11 @@ public class ConfigJsonV1 implements ConfigJson {
     return null;
   }
 
+  @Override
+  public ConfigJsonV2.SolverRemote getSolverRemote() {
+    return null;
+  }
+
   public ConfigJsonV2 toConfigV2() {
     return new ConfigJsonV2()
       .setDomain(this.getDomain())
diff --git a/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/vo/ConfigJsonV2.java b/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/vo/ConfigJsonV2.java
index f08d8834..cb3c5e2e 100644
--- a/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/vo/ConfigJsonV2.java
+++ b/src/main/java/com/mageddo/dnsproxyserver/config/dataprovider/vo/ConfigJsonV2.java
@@ -2,16 +2,21 @@ package com.mageddo.dnsproxyserver.config.dataprovider.vo;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.datatype.jsr310.deser.DurationDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.DurationSerializer;
 import com.mageddo.dnsproxyserver.config.Config;
 import com.mageddo.dnsproxyserver.config.Config.Entry.Type;
 import com.mageddo.dnsproxyserver.config.dataprovider.mapper.ConfigJsonV2EnvsMapper;
+import com.mageddo.dnsproxyserver.server.dns.SimpleServer;
 import com.mageddo.net.IP;
 import com.mageddo.net.IpAddr;
-import com.mageddo.dnsproxyserver.server.dns.SimpleServer;
 import lombok.Data;
 import lombok.experimental.Accessors;
 
 import java.net.URI;
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -62,6 +67,8 @@ public class ConfigJsonV2 implements ConfigJson {
 
   private Boolean dockerSolverHostMachineFallbackActive;
 
+  private SolverRemote solverRemote;
+
   @JsonIgnore
   public List<IpAddr> getRemoteDnsServers() {
     return this.remoteDnsServers
@@ -144,4 +151,22 @@ public class ConfigJsonV2 implements ConfigJson {
     }
   }
 
+  @Data
+  public static class SolverRemote {
+
+    private CircuitBreaker circuitBreaker;
+
+    @Data
+    public static class CircuitBreaker {
+
+      private Integer failureThreshold;
+      private Integer failureThresholdCapacity;
+      private Integer successThreshold;
+
+      @JsonSerialize(using = DurationSerializer.class)
+      @JsonDeserialize(using = DurationDeserializer.class)
+      private Duration testDelay;
+    }
+
+  }
 }
diff --git a/src/main/java/com/mageddo/dnsproxyserver/config/di/Context.java b/src/main/java/com/mageddo/dnsproxyserver/config/di/Context.java
new file mode 100644
index 00000000..de98838a
--- /dev/null
+++ b/src/main/java/com/mageddo/dnsproxyserver/config/di/Context.java
@@ -0,0 +1,19 @@
+package com.mageddo.dnsproxyserver.config.di;
+
+
+import com.mageddo.dnsproxyserver.config.application.ConfigService;
+import com.mageddo.dnsproxyserver.config.di.module.ModuleConfigDAO;
+import dagger.Component;
+
+import javax.inject.Singleton;
+
+@Singleton
+@Component(modules = ModuleConfigDAO.class)
+public interface Context {
+
+  static Context create() {
+    return DaggerContext.create();
+  }
+
+   ConfigService configService();
+}
diff --git a/src/main/java/com/mageddo/dnsproxyserver/config/di/module/ModuleConfigDAO.java b/src/main/java/com/mageddo/dnsproxyserver/config/di/module/ModuleConfigDAO.java
new file mode 100644
index 00000000..7ea9d395
--- /dev/null
+++ b/src/main/java/com/mageddo/dnsproxyserver/config/di/module/ModuleConfigDAO.java
@@ -0,0 +1,31 @@
+package com.mageddo.dnsproxyserver.config.di.module;
+
+import com.mageddo.di.InstanceImpl;
+import com.mageddo.dnsproxyserver.config.dataprovider.ConfigDAO;
+import com.mageddo.dnsproxyserver.config.dataprovider.ConfigDAOCmdArgs;
+import com.mageddo.dnsproxyserver.config.dataprovider.ConfigDAOEnv;
+import com.mageddo.dnsproxyserver.config.dataprovider.ConfigDAOJson;
+import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.ElementsIntoSet;
+
+import javax.enterprise.inject.Instance;
+import javax.inject.Singleton;
+import java.util.Set;
+
+@Module
+public interface ModuleConfigDAO {
+  @Provides
+  static Instance<ConfigDAO> multiSourceConfigDAOInstance(Set<ConfigDAO> instances){
+    return new InstanceImpl<>(instances);
+  }
+
+  @Provides
+  @Singleton
+  @ElementsIntoSet
+  static Set<ConfigDAO> configDaos(
+      ConfigDAOEnv o1, ConfigDAOCmdArgs o2, ConfigDAOJson o3
+  ) {
+    return Set.of(o1, o2, o3);
+  }
+}
diff --git a/src/main/java/com/mageddo/dnsproxyserver/config/mapper/ConfigMapper.java b/src/main/java/com/mageddo/dnsproxyserver/config/mapper/ConfigMapper.java
index 47ebfdc0..cfa7eb54 100644
--- a/src/main/java/com/mageddo/dnsproxyserver/config/mapper/ConfigMapper.java
+++ b/src/main/java/com/mageddo/dnsproxyserver/config/mapper/ConfigMapper.java
@@ -1,6 +1,8 @@
 package com.mageddo.dnsproxyserver.config.mapper;
 
+import com.mageddo.dnsproxyserver.config.CircuitBreaker;
 import com.mageddo.dnsproxyserver.config.Config;
+import com.mageddo.dnsproxyserver.config.SolverRemote;
 import com.mageddo.dnsproxyserver.config.dataprovider.ConfigPropDAO;
 import com.mageddo.dnsproxyserver.server.dns.SimpleServer;
 import com.mageddo.dnsproxyserver.utils.Numbers;
@@ -9,6 +11,8 @@ import org.apache.commons.lang3.SystemUtils;
 import org.apache.commons.lang3.Validate;
 
 import java.net.URI;
+import java.time.Duration;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -18,6 +22,12 @@ import static com.mageddo.dnsproxyserver.utils.ObjectUtils.firstNonNullRequiring
 
 public class ConfigMapper {
   public static Config mapFrom(List<Config> configs) {
+    final var configsWithDefault = new ArrayList<>(configs);
+    configsWithDefault.add(buildDefault());
+    return mapFrom0(configsWithDefault);
+  }
+
+  private static Config mapFrom0(List<Config> configs) {
     final var config = Config.builder()
       .version(ConfigPropDAO.getVersion())
       .webServerPort(Numbers.firstPositive(mapField(Config::getWebServerPort, configs)))
@@ -30,21 +40,46 @@ public class ConfigMapper {
       .domain(firstNonNullRequiring(mapField(Config::getDomain, configs)))
       .mustConfigureDpsNetwork(firstNonNullRequiring(mapField(Config::getMustConfigureDpsNetwork, configs)))
       .dpsNetworkAutoConnect(firstNonNullRequiring(mapField(Config::getDpsNetworkAutoConnect, configs)))
-      .remoteDnsServers(firstNonEmptyListRequiring(mapField(Config::getRemoteDnsServers, configs, buildDefaultDnsServers())))
+      .remoteDnsServers(firstNonEmptyListRequiring(mapField(Config::getRemoteDnsServers, configs)))
       .configPath(firstNonNullRequiring(mapField(Config::getConfigPath, configs)))
       .resolvConfPaths(firstNonNullRequiring(mapField(Config::getResolvConfPaths, configs)))
-      .serverProtocol(firstNonNullRequiring(mapField(Config::getServerProtocol, configs, SimpleServer.Protocol.UDP_TCP)))
-      .dockerHost(firstNonNullRequiring(mapField(Config::getDockerHost, configs, buildDefaultDockerHost())))
+      .serverProtocol(firstNonNullRequiring(mapField(Config::getServerProtocol, configs)))
+      .dockerHost(firstNonNullRequiring(mapField(Config::getDockerHost, configs)))
       .resolvConfOverrideNameServers(firstNonNullRequiring(mapField(Config::getResolvConfOverrideNameServers, configs)))
       .noRemoteServers(firstNonNullRequiring(mapField(Config::getNoRemoteServers, configs)))
       .noEntriesResponseCode(firstNonNullRequiring(mapField(Config::getNoEntriesResponseCode, configs)))
       .dockerSolverHostMachineFallbackActive(firstNonNullRequiring(mapField(Config::getDockerSolverHostMachineFallbackActive, configs)))
+      .solverRemote(firstNonNullRequiring(mapField(Config::getSolverRemote, configs)))
       .build();
     validate(config);
     return config;
   }
 
-  static void validate(Config config) {
+  private static Config buildDefault() {
+    return Config
+      .builder()
+      .serverProtocol(SimpleServer.Protocol.UDP_TCP)
+      .dockerHost(buildDefaultDockerHost())
+      .remoteDnsServers(Collections.singletonList(IpAddr.of("8.8.8.8:53")))
+      .solverRemote(SolverRemote
+        .builder()
+        .circuitBreaker(defaultCircuitBreaker())
+        .build()
+      )
+      .build();
+  }
+
+  public static CircuitBreaker defaultCircuitBreaker() {
+    return CircuitBreaker
+      .builder()
+      .failureThreshold(3)
+      .failureThresholdCapacity(10)
+      .successThreshold(5)
+      .testDelay(Duration.ofSeconds(20))
+      .build();
+  }
+
+  private static void validate(Config config) {
     Validate.notNull(config.getVersion());
     Validate.notNull(config.getRemoteDnsServers());
     Validate.isTrue(config.getWebServerPort() != null && config.getWebServerPort() > 0);
@@ -56,11 +91,11 @@ public class ConfigMapper {
     Validate.notNull(config.getMustConfigureDpsNetwork());
     Validate.notNull(config.getDpsNetworkAutoConnect());
     Validate.notNull(config.getResolvConfPaths());
+    Validate.notNull(config.getSolverRemote());
+    Validate.notNull(config.getDockerSolverHostMachineFallbackActive());
+    Validate.notNull(config.getNoRemoteServers());
     Validate.notNull(config.getServerProtocol());
-  }
-
-  static List<IpAddr> buildDefaultDnsServers() {
-    return Collections.singletonList(IpAddr.of("8.8.8.8:53"));
+    Validate.notNull(config.getResolvConfOverrideNameServers());
   }
 
   private static URI buildDefaultDockerHost() {
diff --git a/src/main/java/com/mageddo/dnsproxyserver/di/Context.java b/src/main/java/com/mageddo/dnsproxyserver/di/Context.java
index caf98249..7d92ff9b 100644
--- a/src/main/java/com/mageddo/dnsproxyserver/di/Context.java
+++ b/src/main/java/com/mageddo/dnsproxyserver/di/Context.java
@@ -1,6 +1,7 @@
 package com.mageddo.dnsproxyserver.di;
 
 import com.mageddo.di.CDIImpl;
+import com.mageddo.dnsproxyserver.config.di.module.ModuleConfigDAO;
 import com.mageddo.dnsproxyserver.di.module.ModuleDao;
 import com.mageddo.dnsproxyserver.di.module.ModuleDockerClient;
 import com.mageddo.dnsproxyserver.di.module.ModuleHttpMapper;
@@ -34,7 +35,8 @@ import java.util.Set;
   ModuleHttpMapper.class,
   ModuleSolver.class,
   ModuleStartup.class,
-  ModuleMap.class
+  ModuleMap.class,
+  ModuleConfigDAO.class
 })
 public interface Context {
 
diff --git a/src/main/java/com/mageddo/dnsproxyserver/server/dns/solver/SolverRemote.java b/src/main/java/com/mageddo/dnsproxyserver/server/dns/solver/SolverRemote.java
index fa2bbeb1..99da9571 100644
--- a/src/main/java/com/mageddo/dnsproxyserver/server/dns/solver/SolverRemote.java
+++ b/src/main/java/com/mageddo/dnsproxyserver/server/dns/solver/SolverRemote.java
@@ -3,6 +3,7 @@ package com.mageddo.dnsproxyserver.server.dns.solver;
 import com.mageddo.commons.circuitbreaker.CircuitCheckException;
 import com.mageddo.commons.concurrent.ThreadPool;
 import com.mageddo.commons.concurrent.Threads;
+import com.mageddo.dnsproxyserver.config.application.ConfigService;
 import com.mageddo.dnsproxyserver.server.dns.Messages;
 import com.mageddo.net.Networks;
 import dev.failsafe.CircuitBreaker;
@@ -45,6 +46,7 @@ public class SolverRemote implements Solver {
   private final RemoteResolvers delegate;
   private final Map<InetSocketAddress, CircuitBreaker<Response>> circuitBreakerMap = new ConcurrentHashMap<>();
   private final ExecutorService threadPool = ThreadPool.newFixed(50);
+  private final ConfigService configService;
   private String status;
 
   @Override
@@ -166,15 +168,23 @@ public class SolverRemote implements Solver {
   }
 
   private CircuitBreaker<Response> circuitBreakerFor(InetSocketAddress address) {
-    return this.circuitBreakerMap.computeIfAbsent(address, inetSocketAddress -> {
-      final var breaker = CircuitBreaker.<Response>builder()
-        .handle(CircuitCheckException.class)
-        .withFailureThreshold(3, 10)
-        .withSuccessThreshold(5)
-        .withDelay(Duration.ofSeconds(20))
-        .build();
-      return breaker;
-    });
+    final var config = this.findCircuitBreakerConfig();
+    return this.circuitBreakerMap.computeIfAbsent(address, inetSocketAddress -> buildCircuitBreaker(config));
+  }
+
+  private static CircuitBreaker<Response> buildCircuitBreaker(com.mageddo.dnsproxyserver.config.CircuitBreaker config) {
+    return CircuitBreaker.<Response>builder()
+      .handle(CircuitCheckException.class)
+      .withFailureThreshold(config.getFailureThreshold(), config.getFailureThresholdCapacity())
+      .withSuccessThreshold(config.getSuccessThreshold())
+      .withDelay(config.getTestDelay())
+      .build();
+  }
+
+  com.mageddo.dnsproxyserver.config.CircuitBreaker findCircuitBreakerConfig() {
+    return this.configService.findCurrentConfig()
+      .getSolverRemote()
+      .getCircuitBreaker();
   }
 
   String getStatus() {
diff --git a/src/main/java/com/mageddo/json/JsonUtils.java b/src/main/java/com/mageddo/json/JsonUtils.java
index 331982aa..f5072158 100644
--- a/src/main/java/com/mageddo/json/JsonUtils.java
+++ b/src/main/java/com/mageddo/json/JsonUtils.java
@@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 
 
 import java.io.BufferedReader;
@@ -56,8 +57,9 @@ public final class JsonUtils {
   public static ObjectMapper objectMapper() {
     final SimpleModule m = new SimpleModule();
     return new ObjectMapper()
-        .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
-        .registerModule(m);
+      .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
+      .registerModule(new JavaTimeModule())
+      .registerModule(m);
   }
 
   public static ObjectMapper setInstance(ObjectMapper objectMapper) {


Test patch:
diff --git a/src/test/java/com/mageddo/dnsproxyserver/config/application/ConfigServiceCompTest.java b/src/test/java/com/mageddo/dnsproxyserver/config/application/ConfigServiceCompTest.java
index eedbe610..34c27273 100644
--- a/src/test/java/com/mageddo/dnsproxyserver/config/application/ConfigServiceCompTest.java
+++ b/src/test/java/com/mageddo/dnsproxyserver/config/application/ConfigServiceCompTest.java
@@ -1,11 +1,10 @@
 package com.mageddo.dnsproxyserver.config.application;
 
+import com.mageddo.dnsproxyserver.config.Config;
 import com.mageddo.dnsproxyserver.config.LogLevel;
-import com.mageddo.dnsproxyserver.config.configurator.Context;
+import com.mageddo.dnsproxyserver.config.di.Context;
 import com.mageddo.dnsproxyserver.config.dataprovider.ConfigDAOCmdArgs;
 import dagger.sheath.junit.DaggerTest;
-import lombok.SneakyThrows;
-import org.apache.commons.io.IOUtils;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.io.TempDir;
 
@@ -15,15 +14,9 @@ import java.nio.file.Path;
 
 import static com.mageddo.utils.TestUtils.readAndSortJson;
 import static com.mageddo.utils.TestUtils.readAndSortJsonExcluding;
-import static com.mageddo.utils.TestUtils.readAsStream;
-import static com.mageddo.utils.TestUtils.sortJsonExcluding;
-import static org.hamcrest.CoreMatchers.anyOf;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
-import static testing.JsonAssertion.jsonPath;
 
 @DaggerTest(component = Context.class)
 class ConfigServiceCompTest {
@@ -48,7 +41,7 @@ class ConfigServiceCompTest {
   }
 
   @Test
-  void mustParseDefaultConfigsAndCreateConfigFile(@TempDir Path tmpDir) {
+  void mustParseDefaultConfigsAndCreateJsonConfigFile(@TempDir Path tmpDir) {
 
     // arrange
     final var jsonConfigFile = tmpDir.resolve("tmpfile.json");
@@ -62,46 +55,20 @@ class ConfigServiceCompTest {
       ;
 
     // assert
+    assertParsedConfig(config);
+    assertWrittenFile(jsonConfigFile);
+  }
+
+  static void assertParsedConfig(Config config) {
     assertEquals(
       readAndSortJsonExcluding("/configs-test/001.json", excludingFields),
       readAndSortJsonExcluding(config, excludingFields)
     );
-    assertTrue(Files.exists(jsonConfigFile));
-    assertEquals(readAndSortJson("/configs-test/002.json"), readAndSortJson(jsonConfigFile));
   }
 
-
-  @Test
-  @SneakyThrows
-  void mustRespectStoredConfig(@TempDir Path tmpDir) {
-
-    // arrange
-    final var jsonConfigFile = "/configs-test/003.json";
-    final var tmpConfigFile = tmpDir.resolve("tmpfile.json");
-
-    try (var out = Files.newOutputStream(tmpConfigFile)) {
-      IOUtils.copy(readAsStream(jsonConfigFile), out);
-    }
-    assertTrue(Files.exists(tmpConfigFile));
-
-    ConfigDAOCmdArgs.setArgs(new String[]{"--conf-path", tmpConfigFile.toString()});
-
-    // act
-    final var config = Configs.getContext()
-      .configService()
-      .findCurrentConfig()
-      ;
-
-    // assert
-    assertEquals(
-      readAndSortJsonExcluding("/configs-test/004.json", excludingFields),
-      sortJsonExcluding(config, excludingFields)
-    );
-    assertThat(
-      jsonPath(config).getString("dockerHost"),
-      anyOf(containsString("unix:"), containsString("npipe"))
-    );
-
+  static void assertWrittenFile(Path jsonConfigFile) {
+    assertTrue(Files.exists(jsonConfigFile));
+    assertEquals(readAndSortJson("/configs-test/002.json"), readAndSortJson(jsonConfigFile));
   }
 
   @Test
diff --git a/src/test/java/com/mageddo/dnsproxyserver/config/dataprovider/ConfigDAOJsonTest.java b/src/test/java/com/mageddo/dnsproxyserver/config/dataprovider/ConfigDAOJsonTest.java
index aca9afb9..07d20983 100644
--- a/src/test/java/com/mageddo/dnsproxyserver/config/dataprovider/ConfigDAOJsonTest.java
+++ b/src/test/java/com/mageddo/dnsproxyserver/config/dataprovider/ConfigDAOJsonTest.java
@@ -1,16 +1,33 @@
 package com.mageddo.dnsproxyserver.config.dataprovider;
 
+import lombok.SneakyThrows;
+import org.apache.commons.io.IOUtils;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.api.io.TempDir;
+import org.mockito.junit.jupiter.MockitoExtension;
 import testing.templates.ConfigFlagTemplates;
 
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 
+import static com.mageddo.utils.TestUtils.readAndSortJsonExcluding;
+import static com.mageddo.utils.TestUtils.readAsStream;
+import static com.mageddo.utils.TestUtils.sortJsonExcluding;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
+@ExtendWith(MockitoExtension.class)
 class ConfigDAOJsonTest {
 
+  static final String[] excludingFields = new String[]{
+    "version", "configPath", "resolvConfPaths",
+    "dockerHost"
+  };
+
+  final ConfigDAOJson configDAOJson = new ConfigDAOJson(null, null);
+
   @Test
   void mustBuildConfPathRelativeToWorkDir(@TempDir Path tmpDir){
     // arrange
@@ -26,6 +43,30 @@ class ConfigDAOJsonTest {
     assertEquals(workDir.getFileName().toString(), configPath.getParent().getParent().getFileName().toString());
   }
 
+  @Test
+  void mustReadAndRespectStoredConfigFile(@TempDir Path tmpDir) {
+    // arrange
+    final var sorceConfigFile = "/configs-test/003.json";
+    final var configPathToUse = tmpDir.resolve("tmpfile.json");
+    writeCurrentConfigFile(sorceConfigFile, configPathToUse);
+    assertTrue(Files.exists(configPathToUse));
+
+    // act
+    final var config = this.configDAOJson.find(configPathToUse);
+
+    // assert
+    assertEquals(
+      readAndSortJsonExcluding("/configs-test/004.json", excludingFields),
+      sortJsonExcluding(config, excludingFields)
+    );
+  }
+
+  @SneakyThrows
+  static void writeCurrentConfigFile(String sourceResource, Path target) {
+    try (var out = Files.newOutputStream(target)) {
+      IOUtils.copy(readAsStream(sourceResource), out);
+    }
+  }
 
 
 }
diff --git a/src/test/java/com/mageddo/dnsproxyserver/config/mapper/ConfigMapperTest.java b/src/test/java/com/mageddo/dnsproxyserver/config/mapper/ConfigMapperTest.java
new file mode 100644
index 00000000..97bf5a67
--- /dev/null
+++ b/src/test/java/com/mageddo/dnsproxyserver/config/mapper/ConfigMapperTest.java
@@ -0,0 +1,25 @@
+package com.mageddo.dnsproxyserver.config.mapper;
+
+import org.junit.jupiter.api.Test;
+import testing.templates.ConfigTemplates;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+
+class ConfigMapperTest {
+
+  @Test
+  void mustMapFromDaoConfigsToCurrentConfig() {
+    // arrange
+    final var config = ConfigTemplates.defaultWithoutId();
+
+    // act
+    final var currentConfig = ConfigMapper.mapFrom(List.of(config));
+
+    // assert
+    assertNotNull(currentConfig);
+  }
+
+}
diff --git a/src/test/java/com/mageddo/dnsproxyserver/server/dns/solver/SolverRemoteTest.java b/src/test/java/com/mageddo/dnsproxyserver/server/dns/solver/SolverRemoteTest.java
index 4365cba7..a4a6ad60 100644
--- a/src/test/java/com/mageddo/dnsproxyserver/server/dns/solver/SolverRemoteTest.java
+++ b/src/test/java/com/mageddo/dnsproxyserver/server/dns/solver/SolverRemoteTest.java
@@ -8,6 +8,7 @@ import org.mockito.Spy;
 import org.mockito.junit.jupiter.MockitoExtension;
 import org.xbill.DNS.Flags;
 import org.xbill.DNS.Rcode;
+import testing.templates.CircuitBreakerTemplates;
 import testing.templates.InetSocketAddressTemplates;
 import testing.templates.MessageTemplates;
 
@@ -44,6 +45,10 @@ class SolverRemoteTest {
     final var query = MessageTemplates.acmeAQuery();
     final var answer = MessageTemplates.buildAAnswer(query);
 
+    doReturn(CircuitBreakerTemplates.buildDefault())
+      .when(this.solverRemote)
+      .findCircuitBreakerConfig();
+
     doReturn(InetSocketAddressTemplates._8_8_8_8())
       .when(this.resolver)
       .getAddress()
@@ -72,6 +77,10 @@ class SolverRemoteTest {
     final var query = MessageTemplates.acmeAQuery();
     final var answer = MessageTemplates.buildNXAnswer(query);
 
+    doReturn(CircuitBreakerTemplates.buildDefault())
+      .when(this.solverRemote)
+      .findCircuitBreakerConfig();
+
     doReturn(InetSocketAddressTemplates._8_8_8_8())
       .when(this.resolver)
       .getAddress()
@@ -95,9 +104,12 @@ class SolverRemoteTest {
   }
 
   @Test
-  void mustReturnNullWhenGetTimeout() throws Exception {
+  void mustReturnNullWhenGetTimeout() {
+
     // arrange
-    final var query = MessageTemplates.acmeAQuery();
+    doReturn(CircuitBreakerTemplates.buildDefault())
+      .when(this.solverRemote)
+      .findCircuitBreakerConfig();
 
     doReturn(InetSocketAddressTemplates._8_8_8_8())
       .when(this.resolver)
@@ -106,13 +118,15 @@ class SolverRemoteTest {
 
     doReturn(CompletableFuture.failedFuture(new SocketTimeoutException("Deu ruim")))
       .when(this.resolver)
-        .sendAsync(any());
+      .sendAsync(any());
 
     doReturn(List.of(this.resolver))
       .when(this.resolvers)
       .resolvers()
     ;
 
+    final var query = MessageTemplates.acmeAQuery();
+
     // act
     final var res = this.solverRemote.handle(query);
 
@@ -127,6 +141,10 @@ class SolverRemoteTest {
     final var res = MessageTemplates.buildAAnswer(query);
     res.getHeader().unsetFlag(Flags.RA);
 
+    doReturn(CircuitBreakerTemplates.buildDefault())
+      .when(this.solverRemote)
+      .findCircuitBreakerConfig();
+
     doReturn(InetSocketAddressTemplates._8_8_8_8())
       .when(this.resolver)
       .getAddress()
@@ -153,9 +171,11 @@ class SolverRemoteTest {
   @Test
   void mustOpenCircuitAfterThresholdFailures() throws Exception {
     // arrange
-    final var query = MessageTemplates.acmeAQuery();
+    doReturn(CircuitBreakerTemplates.buildDefault())
+      .when(this.solverRemote)
+      .findCircuitBreakerConfig();
 
-    doReturn(InetSocketAddressTemplates._8_8_8_8())
+     doReturn(InetSocketAddressTemplates._8_8_8_8())
       .when(this.resolver)
       .getAddress()
     ;
@@ -168,9 +188,9 @@ class SolverRemoteTest {
       .when(this.resolvers)
       .resolvers()
     ;
+    final var query = MessageTemplates.acmeAQuery();
 
     // act
-    // assert
     assertNull(this.solverRemote.handle(query));
     assertEquals("CircuitCheckException for /8.8.8.8:53", this.solverRemote.getStatus());
 
@@ -180,6 +200,7 @@ class SolverRemoteTest {
     assertNull(this.solverRemote.handle(query));
     assertEquals("CircuitCheckException for /8.8.8.8:53", this.solverRemote.getStatus());
 
+    // assert
     assertNull(this.solverRemote.handle(query));
     assertEquals("CircuitBreakerOpenException for /8.8.8.8:53", this.solverRemote.getStatus());
 
@@ -192,6 +213,10 @@ class SolverRemoteTest {
     final var query = MessageTemplates.acmeAQuery();
     final var res = MessageTemplates.acmeAResponse();
 
+    doReturn(CircuitBreakerTemplates.buildDefault())
+      .when(this.solverRemote)
+      .findCircuitBreakerConfig();
+
     doReturn(InetSocketAddressTemplates._8_8_8_8())
       .when(this.resolver)
       .getAddress()
diff --git a/src/test/java/testing/templates/CircuitBreakerTemplates.java b/src/test/java/testing/templates/CircuitBreakerTemplates.java
new file mode 100644
index 00000000..842b26ea
--- /dev/null
+++ b/src/test/java/testing/templates/CircuitBreakerTemplates.java
@@ -0,0 +1,10 @@
+package testing.templates;
+
+import com.mageddo.dnsproxyserver.config.CircuitBreaker;
+import com.mageddo.dnsproxyserver.config.mapper.ConfigMapper;
+
+public class CircuitBreakerTemplates {
+  public static CircuitBreaker buildDefault(){
+    return ConfigMapper.defaultCircuitBreaker();
+  }
+}
diff --git a/src/test/java/testing/templates/ConfigTemplates.java b/src/test/java/testing/templates/ConfigTemplates.java
index 42c85869..5f9e819c 100644
--- a/src/test/java/testing/templates/ConfigTemplates.java
+++ b/src/test/java/testing/templates/ConfigTemplates.java
@@ -30,6 +30,10 @@ public class ConfigTemplates {
       .logLevel(LogLevel.WARNING)
       .resolvConfPaths(ConfigEnv.DEFAULT_RESOLV_CONF_PATH)
       .serverProtocol(SimpleServer.Protocol.UDP_TCP)
+      .resolvConfOverrideNameServers(true)
+      .noRemoteServers(false)
+      .noEntriesResponseCode(3)
+      .dockerSolverHostMachineFallbackActive(true)
       ;
   }
 
diff --git a/src/test/resources/config-json-v1-test/002.json b/src/test/resources/config-json-v1-test/002.json
index acbb2051..eff82f69 100644
--- a/src/test/resources/config-json-v1-test/002.json
+++ b/src/test/resources/config-json-v1-test/002.json
@@ -28,5 +28,6 @@
   "version" : 2,
   "resolvConfOverrideNameServers" : null,
   "serverProtocol" : null,
-  "webServerPort" : 0
+  "webServerPort" : 0,
+  "solverRemote": null
 }
diff --git a/src/test/resources/configs-test/001.json b/src/test/resources/configs-test/001.json
index 06159991..3367822e 100644
--- a/src/test/resources/configs-test/001.json
+++ b/src/test/resources/configs-test/001.json
@@ -19,6 +19,14 @@
   } ],
   "resolvConfOverrideNameServers" : true,
   "serverProtocol" : "UDP_TCP",
+  "solverRemote" : {
+    "circuitBreaker" : {
+      "failureThreshold" : 3,
+      "failureThresholdCapacity" : 10,
+      "successThreshold" : 5,
+      "testDelay" : 20.0
+    }
+  },
   "versionCmd" : false,
   "webServerPort" : 5380
 }
diff --git a/src/test/resources/configs-test/002.json b/src/test/resources/configs-test/002.json
index 76802aef..dd202713 100644
--- a/src/test/resources/configs-test/002.json
+++ b/src/test/resources/configs-test/002.json
@@ -28,5 +28,6 @@
   "version" : 2,
   "resolvConfOverrideNameServers" : null,
   "serverProtocol" : null,
-  "webServerPort" : null
+  "webServerPort" : null,
+  "solverRemote": null
 }
diff --git a/src/test/resources/configs-test/003.json b/src/test/resources/configs-test/003.json
index 46b1726c..beae42f1 100644
--- a/src/test/resources/configs-test/003.json
+++ b/src/test/resources/configs-test/003.json
@@ -15,5 +15,13 @@
   "hostMachineHostname" : "batata.com",
   "domain" : "acme",
   "dpsNetwork" : true,
-  "dpsNetworkAutoConnect" : true
+  "dpsNetworkAutoConnect" : true,
+  "solverRemote" : {
+    "circuitBreaker" : {
+      "failureThreshold" : 3,
+      "failureThresholdCapacity" : 10,
+      "successThreshold" : 5,
+      "testDelay" : "PT1M"
+    }
+  }
 }
diff --git a/src/test/resources/configs-test/004.json b/src/test/resources/configs-test/004.json
index 61b13d93..8bad086a 100644
--- a/src/test/resources/configs-test/004.json
+++ b/src/test/resources/configs-test/004.json
@@ -1,7 +1,7 @@
 {
   "defaultDns" : false,
   "dnsServerPort" : 5391,
-  "dockerSolverHostMachineFallbackActive" : true,
+  "dockerSolverHostMachineFallbackActive" : null,
   "domain" : "acme",
   "dpsNetworkAutoConnect" : true,
   "helpCmd" : false,
@@ -9,16 +9,20 @@
   "logFile" : "/var/log/dns-proxy-server.log",
   "logLevel" : "DEBUG",
   "mustConfigureDpsNetwork" : true,
-  "noEntriesResponseCode" : 3,
-  "noRemoteServers" : false,
+  "noEntriesResponseCode" : null,
+  "noRemoteServers" : null,
   "registerContainerNames" : true,
-  "remoteDnsServers" : [ {
-    "ip" : "8.8.8.8",
-    "port" : 53,
-    "rawIP" : "8.8.8.8"
-  } ],
-  "resolvConfOverrideNameServers" : true,
-  "serverProtocol" : "UDP_TCP",
+  "remoteDnsServers" : [ ],
+  "resolvConfOverrideNameServers" : null,
+  "serverProtocol" : null,
+  "solverRemote" : {
+    "circuitBreaker" : {
+      "failureThreshold" : 3,
+      "failureThresholdCapacity" : 10,
+      "successThreshold" : 5,
+      "testDelay" : 60.0
+    }
+  },
   "versionCmd" : false,
   "webServerPort" : 9393
 }
diff --git a/src/test/resources/json-configs-test/001.json b/src/test/resources/json-configs-test/001.json
index b682a129..f924fafd 100644
--- a/src/test/resources/json-configs-test/001.json
+++ b/src/test/resources/json-configs-test/001.json
@@ -35,5 +35,6 @@
   "version": 2,
   "resolvConfOverrideNameServers" : null,
   "serverProtocol" : null,
-  "webServerPort": 0
+  "webServerPort": 0,
+  "solverRemote" : null
 }