diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index 5b1270409d45a971d16767f8466607d52e9311c5..1ed4fb19502796feb4a19048806e259efc86dad6 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 2.7.2
+current_version = 2.7.10
commit = True
tag = True
tag_name = {new_version}
diff --git a/Dockerfile b/Dockerfile
index 1ddc78d9a19badff6f0c0081dc2794f87b04b77f..b79069b160c39e7a671f160fdf3553c05ebd8258 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -19,16 +19,22 @@ ARG BUILD_DATE
ARG VCS_REF
ARG VERSION
+ENV CONTEXT_PATH "/services"
+
+RUN apk add --update --no-cache curl
+
COPY docker/config/application.tmpl /config/application.tmpl
COPY docker/README.md docker/run.sh /
COPY --from=java-build-env /project/target/portal-backend.jar /usr/share/jars/
-# 8080: Web service API, health checks on http://host:8087/health
+ENTRYPOINT ["/run.sh"]
+
+# 8080: Web service API, health checks on http://host:8080/$CONTEXT_PATH/health
# 4089: Akka cluster
EXPOSE 4089 8080
-ENTRYPOINT ["/run.sh"]
+HEALTHCHECK --start-period=60s CMD curl -v --silent http://localhost:8080/$CONTEXT_PATH/health 2>&1 | grep UP
LABEL org.label-schema.build-date=$BUILD_DATE \
org.label-schema.name="hbpmip/portal-backend" \
diff --git a/docker/config/application.tmpl b/docker/config/application.tmpl
index 911af6200bda7587d08d1543ad269d969fba3c81..9a56dad4cd7bcdc5d78db3b07473f28521149358 100644
--- a/docker/config/application.tmpl
+++ b/docker/config/application.tmpl
@@ -78,15 +78,9 @@ endpoints:
enabled: true
health:
enabled: true
- endoint: /health
- sentitive: false
+ endpoint: /health
+ sensitive: false
services:
exareme:
miningExaremeUrl: {{ default .Env.EXAREME_URL "http://localhost:9090" }}/mining/query
-
-akka:
- woken:
- host: {{ default .Env.WOKEN_PORT_8088_TCP_ADDR "woken" }}
- port: {{ default .Env.WOKEN_PORT_8088_TCP_PORT "8088" }}
- path: {{ default .Env.WOKEN_AKKA_PATH "/user/entrypoint" }}
diff --git a/hbp.yml b/hbp.yml
index 9cf5b11bf8e83fd71aeefd6de25a08c7b93c7905..a7c40057acc24c34509d2baa0ee4facc1c9f42bf 100644
--- a/hbp.yml
+++ b/hbp.yml
@@ -58,9 +58,9 @@ testing:
command: ./test.sh
release_management:
- current_version: 2.7.2
- current_code_release: https://github.com/HBPMedical/portal-backend/archive/2.7.2.zip
- current_binary_release: https://pypi.python.org/pypi/portal-backend/2.7.2
+ current_version: 2.7.10
+ current_code_release: https://github.com/HBPMedical/portal-backend/archive/2.7.10.zip
+ current_binary_release: https://pypi.python.org/pypi/portal-backend/2.7.10
release_script: 'publish.sh'
continuous_integration:
@@ -75,10 +75,10 @@ continuous_integration:
distribution:
docker_hub:
name: hbpmip/portal-backend
- current_tag: 2.7.2
+ current_tag: 2.7.10
url: https://hub.docker.com/r/hbpmip/portal-backend/
badge: https://img.shields.io/badge/docker-hbpmip%2Fportal--backend-008bb8.svg
- command: docker pull hbpmip/portal-backend:2.7.2
+ command: docker pull hbpmip/portal-backend:2.7.10
planning:
github:
diff --git a/pom.xml b/pom.xml
index 51625bdc02a5e7e6ba56db4806281701d3876aac..517a89dcc9f0b65d0a17ba40bb9f364ec648b62d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
<groupId>eu.hbp.mip</groupId>
<artifactId>portal-backend</artifactId>
- <version>2.7.2</version><!-- BUMP_VERSION -->
+ <version>2.7.10</version><!-- BUMP_VERSION -->
<packaging>jar</packaging>
<name>portal-backend</name>
@@ -47,7 +47,7 @@
<spring-data-jpa.version>1.10.11.RELEASE</spring-data-jpa.version>
<spring-boot-starter-actuator.version>1.4.7.RELEASE</spring-boot-starter-actuator.version>
<aspectjweaver.version>1.8.9</aspectjweaver.version>
- <woken-messages.version>2.7.2</woken-messages.version>
+ <woken-messages.version>2.7.3</woken-messages.version>
<javax-inject.version>1</javax-inject.version>
<akka.version>2.5.12</akka.version>
<spring-context.version>4.3.4.RELEASE</spring-context.version>
diff --git a/src/main/java/eu/hbp/mip/StartupTasks.java b/src/main/java/eu/hbp/mip/StartupTasks.java
index a72e119529fb6fcd497b8ad90fc0b60d4dd7c14a..b09bc06a5c10842aff6ce5e1aee260c6295b1b58 100644
--- a/src/main/java/eu/hbp/mip/StartupTasks.java
+++ b/src/main/java/eu/hbp/mip/StartupTasks.java
@@ -1,12 +1,12 @@
package eu.hbp.mip;
+import akka.actor.ActorRef;
+import akka.cluster.Cluster;
import ch.chuv.lren.woken.messages.datasets.Dataset;
import com.google.gson.Gson;
import eu.hbp.mip.controllers.DatasetsApi;
import eu.hbp.mip.controllers.MiningApi;
import eu.hbp.mip.controllers.VariablesApi;
-import eu.hbp.mip.model.Algorithm;
-import eu.hbp.mip.model.MiningQuery;
import eu.hbp.mip.model.Variable;
import eu.hbp.mip.repositories.VariableRepository;
import org.slf4j.Logger;
@@ -14,11 +14,12 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
+import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
-import java.util.Collections;
@Component
+@DependsOn("wokenCluster")
public class StartupTasks implements ApplicationListener<ApplicationReadyEvent> {
private static final Logger LOGGER = LoggerFactory.getLogger(StartupTasks.class);
@@ -38,19 +39,25 @@ public class StartupTasks implements ApplicationListener<ApplicationReadyEvent>
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
+
// Pre-fill the local variable repository with the list of datasets, interpreted here as variables
// (a bit like a categorical variable can be split into a set of variables (a.k.a one hot encoding in Data science) )
- try {
- for (Dataset dataset: datasetsApi.fetchDatasets()) {
- final String code = dataset.dataset().code();
- Variable v = variableRepository.findOne(code);
- if (v == null) {
- v = new Variable(code);
- variableRepository.save(v);
+ // Try 5 times, to be more robust in the face of cluster failures / slow startup
+ for (int i = 0; i < 5; i++) {
+ try {
+ for (Dataset dataset : datasetsApi.fetchDatasets()) {
+ final String code = dataset.dataset().code();
+ Variable v = variableRepository.findOne(code);
+ if (v == null) {
+ v = new Variable(code);
+ variableRepository.save(v);
+ }
}
+ LOGGER.info("Datasets fetched from Woken");
+ break;
+ } catch (Exception e) {
+ LOGGER.error("Cannot initialise the variable repository. Is the connection to Woken working?", e);
}
- } catch (Exception e) {
- LOGGER.error("Cannot initialise the variable repository. Is the connection to Woken working?", e);
}
/*
@@ -67,4 +74,5 @@ public class StartupTasks implements ApplicationListener<ApplicationReadyEvent>
LOGGER.info("MIP Portal backend is ready!");
}
+
}
diff --git a/src/main/java/eu/hbp/mip/akka/AkkaClusterHealthCheck.java b/src/main/java/eu/hbp/mip/akka/AkkaClusterHealthCheck.java
new file mode 100644
index 0000000000000000000000000000000000000000..932599223fbf1c160485174faaf76da04db6b864
--- /dev/null
+++ b/src/main/java/eu/hbp/mip/akka/AkkaClusterHealthCheck.java
@@ -0,0 +1,26 @@
+package eu.hbp.mip.akka;
+
+import akka.cluster.Cluster;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.boot.actuate.health.HealthIndicator;
+import org.springframework.stereotype.Component;
+
+
+@Component
+public class AkkaClusterHealthCheck implements HealthIndicator {
+
+ @Autowired
+ private Cluster wokenCluster;
+
+ @Override
+ public Health health() {
+ if (wokenCluster.state().getLeader() == null) {
+ return Health.down().withDetail("Error", "No leader in the cluster").build();
+ } else if (!wokenCluster.state().allRoles().contains("woken")) {
+ return Health.down().withDetail("Error", "Woken server cannot be seen in the cluster").build();
+ }
+ return Health.up().build();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/eu/hbp/mip/akka/WokenClientController.java b/src/main/java/eu/hbp/mip/akka/WokenClientController.java
index 5931c13eb1aa64afdb0b573fb9844b06ad84ead5..5e34b75b38ba7fd8a2a8e14d4b8764acabbbc5ad 100644
--- a/src/main/java/eu/hbp/mip/akka/WokenClientController.java
+++ b/src/main/java/eu/hbp/mip/akka/WokenClientController.java
@@ -2,7 +2,6 @@ package eu.hbp.mip.akka;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
-import akka.cluster.pubsub.DistributedPubSub;
import akka.cluster.pubsub.DistributedPubSubMediator;
import akka.pattern.Patterns;
import akka.util.Timeout;
@@ -19,7 +18,6 @@ import scala.concurrent.ExecutionContext;
import scala.concurrent.Future;
import scala.concurrent.duration.Duration;
-import javax.annotation.PostConstruct;
import java.util.function.Function;
/**
@@ -32,21 +30,12 @@ public abstract class WokenClientController {
@Autowired
private ActorSystem actorSystem;
- @Autowired
- private String wokenReceptionistPath;
-
@Value("#{'${akka.woken.path:/user/entrypoint}'}")
private String wokenPath;
+ @Autowired
private ActorRef wokenMediator;
- @SuppressWarnings("unused")
- @PostConstruct
- public void initClusterClient() {
- LOGGER.info("Start Woken client " + wokenReceptionistPath);
- wokenMediator = DistributedPubSub.get(actorSystem).mediator();
- }
-
@SuppressWarnings("unchecked")
protected <A, B> B askWoken(A message, int waitInSeconds) throws Exception {
LOGGER.info("Akka is trying to reach remote " + wokenPath);
diff --git a/src/main/java/eu/hbp/mip/configuration/AkkaConfiguration.java b/src/main/java/eu/hbp/mip/configuration/AkkaConfiguration.java
index cfcfefe7dbb2bc637e4090a42c037ee1e3563b63..d2f285d4582537c714837d16c17f934f08bc6831 100644
--- a/src/main/java/eu/hbp/mip/configuration/AkkaConfiguration.java
+++ b/src/main/java/eu/hbp/mip/configuration/AkkaConfiguration.java
@@ -1,14 +1,20 @@
package eu.hbp.mip.configuration;
+import akka.actor.ActorRef;
import akka.actor.ActorSystem;
+import akka.actor.ExtendedActorSystem;
+import akka.cluster.Cluster;
+import akka.cluster.pubsub.DistributedPubSub;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.*;
+
+import java.util.List;
+import java.util.concurrent.Semaphore;
import static eu.hbp.mip.akka.SpringExtension.SPRING_EXTENSION_PROVIDER;
@@ -20,30 +26,90 @@ import static eu.hbp.mip.akka.SpringExtension.SPRING_EXTENSION_PROVIDER;
@ComponentScan
class AkkaConfiguration {
+ protected final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
+
@Autowired
private ApplicationContext applicationContext;
- @Value("#{'${akka.woken.host:woken}'}")
- private String wokenHost;
-
- @Value("#{'${akka.woken.port:8088}'}")
- private String wokenPort;
+ private final Config config;
- @Value("#{'${akka.woken.path:/user/entrypoint}'}")
- private String wokenPath;
+ {
+ Config remotingConfig = ConfigFactory.parseResourcesAnySyntax("akka-remoting.conf").resolve();
+ String remotingImpl = remotingConfig.getString("remoting.implementation");
+ config = ConfigFactory
+ .parseString("akka {\n" +
+ " actor.provider = cluster\n" +
+ " extensions += \"akka.cluster.pubsub.DistributedPubSub\"\n" +
+ "}")
+ .withFallback(ConfigFactory.parseResourcesAnySyntax("akka.conf"))
+ .withFallback(ConfigFactory.parseResourcesAnySyntax("akka-" + remotingImpl + "-remoting.conf"))
+ .withFallback(ConfigFactory.parseResourcesAnySyntax("kamon.conf"))
+ .withFallback(ConfigFactory.load())
+ .resolve();
+ }
@Bean
- public ActorSystem actorSystem() {
- Config config = ConfigFactory.load("application.conf");
- ActorSystem system = ActorSystem.create("woken", config);
+ public ExtendedActorSystem actorSystem() {
+ LOGGER.info("Step 1/3: Starting actor system...");
+ LOGGER.info("Create actor system at " + wokenClusterHost() + ":" + wokenClusterPort());
+ ExtendedActorSystem system = (ExtendedActorSystem) ActorSystem.create("woken", config);
SPRING_EXTENSION_PROVIDER.get(system).initialize(applicationContext);
return system;
}
@Bean
- public String wokenReceptionistPath() {
- return "akka.tcp://woken@" + wokenHost + ":" + wokenPort + "/system/receptionist";
+ public Cluster wokenCluster() {
+ Cluster cluster = Cluster.get(actorSystem());
+ LOGGER.info("Connect to Woken cluster nodes at " + String.join(",", wokenPath()));
+ Semaphore semaphore = new Semaphore(1);
+ cluster.registerOnMemberUp( () -> {
+ LOGGER.info("Step 2/3: Cluster up, registering the actors...");
+
+ // Do not call wokenMediator() here to avoid recursive loops
+ ActorRef mediator = DistributedPubSub.get(actorSystem()).mediator();
+
+ LOGGER.info("Woken Mediator available at " + mediator.path().toStringWithoutAddress());
+
+ semaphore.release();
+ });
+
+ try {
+ semaphore.acquire();
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ LOGGER.warn("Cannot wait for Akka cluster start", e);
+ }
+
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ cluster.leave(cluster.selfAddress());
+ })
+ );
+
+ LOGGER.info("Step 3/3: Cluster connected to Woken.");
+
+ return cluster;
+ }
+
+ @Bean
+ public String wokenClusterHost() {
+ return config.getString("clustering.ip");
+ }
+
+ @Bean
+ public Integer wokenClusterPort() {
+ return config.getInt("clustering.port");
}
+ @Bean
+ public List<String> wokenPath() {
+ return config.getStringList("akka.cluster.seed-nodes");
+ }
+
+ @Bean
+ @Lazy
+ @DependsOn("wokenCluster")
+ public ActorRef wokenMediator() {
+ return DistributedPubSub.get(actorSystem()).mediator();
+ }
}
diff --git a/src/main/java/eu/hbp/mip/configuration/WebConfiguration.java b/src/main/java/eu/hbp/mip/configuration/WebConfiguration.java
index fb41a0da12783723de821f00eb04e24f05679b0b..eb84126ff753b3b458995030ee8faf429ae5e5e9 100644
--- a/src/main/java/eu/hbp/mip/configuration/WebConfiguration.java
+++ b/src/main/java/eu/hbp/mip/configuration/WebConfiguration.java
@@ -2,6 +2,7 @@ package eu.hbp.mip.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.DependsOn;
import org.springframework.data.web.config.EnableSpringDataWebSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
@@ -19,6 +20,7 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
@EnableSpringDataWebSupport
+@DependsOn("wokenCluster")
public class WebConfiguration {
@Bean
diff --git a/src/main/java/eu/hbp/mip/controllers/VariablesApi.java b/src/main/java/eu/hbp/mip/controllers/VariablesApi.java
index 1c284f1bbb406e3907ee28888d88aa250757ad5d..3b5b07feeb0351a489e10d39f882aa3ef3be0bb9 100644
--- a/src/main/java/eu/hbp/mip/controllers/VariablesApi.java
+++ b/src/main/java/eu/hbp/mip/controllers/VariablesApi.java
@@ -5,10 +5,15 @@
package eu.hbp.mip.controllers;
+import ch.chuv.lren.mip.portal.WokenConversions;
+import ch.chuv.lren.woken.messages.variables.VariableMetaData;
+import ch.chuv.lren.woken.messages.variables.VariablesForDatasetsQuery;
+import ch.chuv.lren.woken.messages.variables.VariablesForDatasetsResponse;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
+import eu.hbp.mip.akka.WokenClientController;
import eu.hbp.mip.model.Algorithm;
import eu.hbp.mip.model.MiningQuery;
import eu.hbp.mip.model.Variable;
@@ -20,11 +25,14 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
+import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.web.bind.annotation.*;
+import scala.collection.JavaConversions;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
@@ -35,7 +43,7 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@RestController
@RequestMapping(value = "/variables", produces = {APPLICATION_JSON_VALUE})
@Api(value = "/variables", description = "the variables API")
-public class VariablesApi {
+public class VariablesApi extends WokenClientController {
private static final Logger LOGGER = LoggerFactory.getLogger(VariablesApi.class);
@@ -71,6 +79,38 @@ public class VariablesApi {
return ResponseEntity.ok(variablesObjects);
}
+ @ApiOperation(value = "Get variables available for a dataset", response = List.class, responseContainer = "List")
+ @Cacheable(value = "availableVariables",
+ key = "#datasets",
+ unless = "#result.getStatusCode().value()!=200")
+ @RequestMapping(value = "/availableVariables", method = RequestMethod.GET)
+ public ResponseEntity getAvailableVariables(
+ @ApiParam(value = "List of datasets : ds1,ds2,...") @RequestParam(value = "datasets") String datasets) {
+
+ LOGGER.info("Get available variables for datasets " + datasets);
+
+ List<Variable> dsAsVariables = Arrays.stream(datasets.split(",")).map(Variable::new).collect(Collectors.toList());
+ WokenConversions conv = new WokenConversions();
+
+ VariablesForDatasetsQuery query = new VariablesForDatasetsQuery(conv.toDatasets(dsAsVariables), true);
+
+ return requestWoken(query, 30, r -> {
+ VariablesForDatasetsResponse response = (VariablesForDatasetsResponse) r;
+
+ if (response.error().isDefined()) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response.error().get());
+ } else {
+ List<Variable> variables = new ArrayList<>();
+ for (VariableMetaData var: JavaConversions.setAsJavaSet(response.variables())) {
+ variables.add(new Variable(var.code()));
+ }
+ return ResponseEntity.ok(variables);
+ }
+ });
+
+ }
+
+
@ApiOperation(value = "Get a variable", response = Object.class)
@Cacheable("variable")
@RequestMapping(value = "/{code}", method = RequestMethod.GET)
diff --git a/src/main/resources/akka-artery-remoting.conf b/src/main/resources/akka-artery-remoting.conf
new file mode 100644
index 0000000000000000000000000000000000000000..c89f41b643d8b6cff4ba5480b03bddcd57848348
--- /dev/null
+++ b/src/main/resources/akka-artery-remoting.conf
@@ -0,0 +1,25 @@
+akka {
+
+ remote {
+
+ netty.tcp {
+ enabled = off
+ }
+
+ artery {
+ enabled = on
+ transport = tcp
+
+ canonical.hostname = ${clustering.ip} # external (logical) hostname
+ canonical.port = ${clustering.port} # external (logical) port
+
+ bind.hostname = 0.0.0.0 # internal (bind) hostname
+ bind.port = ${clustering.port} # internal (bind) port
+
+ }
+ }
+}
+
+remoting {
+ protocol = "akka"
+}
diff --git a/src/main/resources/akka-netty-remoting.conf b/src/main/resources/akka-netty-remoting.conf
new file mode 100644
index 0000000000000000000000000000000000000000..2c830d0dc17969d54f8a331196fdb53ba15f18d0
--- /dev/null
+++ b/src/main/resources/akka-netty-remoting.conf
@@ -0,0 +1,28 @@
+akka {
+
+ remote {
+ maximum-payload-bytes = 30000000 bytes
+
+ netty.tcp {
+ hostname = ${clustering.ip} # external (logical) hostname
+ port = ${clustering.port} # external (logical) port
+
+ bind-hostname = 0.0.0.0 # internal (bind) hostname
+ bind-port = ${clustering.port} # internal (bind) port
+
+ message-frame-size = 30000000b
+ send-buffer-size = 30000000b
+ receive-buffer-size = 30000000b
+ maximum-frame-size = 30000000b
+ }
+
+ artery {
+ enabled = off
+
+ }
+ }
+}
+
+remoting {
+ protocol = "akka.tcp"
+}
diff --git a/src/main/resources/akka-remoting.conf b/src/main/resources/akka-remoting.conf
new file mode 100644
index 0000000000000000000000000000000000000000..18f2189d453d0c76cbb94505af6cd735fe7c3ff4
--- /dev/null
+++ b/src/main/resources/akka-remoting.conf
@@ -0,0 +1,7 @@
+remoting {
+
+ implementation = "netty"
+ # Alternative option is 'artery'
+ implementation = ${?AKKA_REMOTING}
+
+}
diff --git a/src/main/resources/akka.conf b/src/main/resources/akka.conf
new file mode 100644
index 0000000000000000000000000000000000000000..b169e7b9c2cc700b878cbce1518ecb18d8a56ebc
--- /dev/null
+++ b/src/main/resources/akka.conf
@@ -0,0 +1,57 @@
+# Merged with defaults in woken-messages/reference.conf
+akka {
+ loglevel = "WARNING"
+ loglevel = ${?LOG_LEVEL}
+ stdout-loglevel = "WARNING"
+ stdout-loglevel = ${?LOG_LEVEL}
+ loggers = ["akka.event.slf4j.Slf4jLogger"]
+ logging-filter = "akka.event.slf4j.Slf4jLoggingFilter"
+
+ log-config-on-start = off
+ log-config-on-start = ${?LOG_CONFIG}
+
+ log-dead-letters = 10
+ log-dead-letters-during-shutdown = off
+
+ actor {
+ # provider = "cluster"
+
+ allow-java-serialization = off
+ enable-additional-serialization-bindings = true
+
+ }
+
+ remote {
+ log-sent-messages = off
+ log-received-messages = off
+ log-remote-lifecycle-events = off
+
+ watch-failure-detector {
+ acceptable-heartbeat-pause = 20 s
+ }
+
+ }
+
+ cluster {
+ seed-nodes = [
+ ${remoting.protocol}"://"${clustering.cluster.name}"@"${clustering.seed-ip}":"${clustering.seed-port}
+ ]
+
+ roles = ["portal"]
+
+ }
+
+ http {
+ server {
+ idle-timeout = 300s
+ request-timeout = 180s
+ ssl-encryption = off
+ ssl-tracing = on
+ }
+
+ client {
+ idle-timeout = 300s
+ request-timeout = 20 s
+ }
+ }
+}
diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf
index 5f553c58dd73df1307ce5d9c6d28c5a48cb05928..333813a1dedc7f79090e077f1d826763ea6521f8 100644
--- a/src/main/resources/application.conf
+++ b/src/main/resources/application.conf
@@ -1,73 +1,3 @@
-akka {
- loglevel = "WARNING"
- loglevel = ${?LOG_LEVEL}
- stdout-loglevel = "WARNING"
- stdout-loglevel = ${?LOG_LEVEL}
- loggers = ["akka.event.slf4j.Slf4jLogger"]
- logging-filter = "akka.event.slf4j.Slf4jLoggingFilter"
+# No specific configuration for Portal backend
+# All configuration is related to Akka
- log-config-on-start = off
- log-config-on-start = ${?LOG_CONFIG}
-
- log-dead-letters = 10
- log-dead-letters-during-shutdown = off
-
- actor {
- provider = "cluster"
-
- allow-java-serialization = off
- enable-additional-serialization-bindings = true
-
- }
-
- remote {
- log-sent-messages = on
- log-received-messages = on
- log-remote-lifecycle-events = on
-
- maximum-payload-bytes = 10000000 bytes
-
- watch-failure-detector {
- acceptable-heartbeat-pause = 20 s
- }
-
- artery {
- enabled = on
- transport = tcp
-
- canonical.hostname = ${clustering.ip} # external (logical) hostname
- canonical.port = ${clustering.port} # external (logical) port
-
- bind.hostname = 0.0.0.0 # internal (bind) hostname
- bind.port = ${clustering.port} # internal (bind) port
-
- }
-
- }
-
- cluster {
- seed-nodes = [
- "akka://"${clustering.cluster.name}"@"${clustering.seed-ip}":"${clustering.seed-port}
- ]
-
- roles = ["portal"]
-
- }
-
- extensions += "akka.cluster.pubsub.DistributedPubSub"
-
-}
-
-clustering {
- ip = "127.0.0.1"
- ip = ${?CLUSTER_IP}
- port = 4089
- port = ${?CLUSTER_PORT}
- seed-ip = "woken"
- seed-ip = ${?CLUSTER_IP}
- seed-ip = ${?WOKEN_PORT_8088_TCP_ADDR}
- seed-port = 8088
- seed-port = ${?WOKEN_PORT_8088_TCP_PORT}
- cluster.name = "woken"
- cluster.name = ${?CLUSTER_NAME}
-}
diff --git a/src/main/resources/kamon.conf b/src/main/resources/kamon.conf
new file mode 100644
index 0000000000000000000000000000000000000000..00b068b2199b6105255f66e86b23d67ece3e75c8
--- /dev/null
+++ b/src/main/resources/kamon.conf
@@ -0,0 +1,65 @@
+kamon {
+ enabled = no
+ enabled = ${?KAMON_ENABLED}
+
+ environment {
+ service = "woken"
+ }
+
+ zipkin = {
+ enabled = no
+ enabled = ${?ZIPKIN_ENABLED}
+ host = "zipkin"
+ host = ${?ZIPKIN_IP}
+ port = 9411
+ port = ${?ZIPKIN_PORT}
+ }
+
+ prometheus = {
+ enabled = no
+ enabled = ${?PROMETHEUS_ENABLED}
+ host = "prometheus"
+ host = ${?PROMETHEUS_IP}
+ port = 9090
+ port = ${?PROMETHEUS_PORT}
+ }
+
+ util.filters {
+ "akka.tracked-actor" {
+ includes = ["**"]
+ }
+
+ "akka.tracked-dispatcher" {
+ includes = ["**"]
+ }
+
+ "akka.traced-actor" {
+ includes = ["**"]
+ }
+
+ }
+
+ akka-http {
+ add-http-status-code-as-metric-tag = true
+ }
+
+ akka {
+ ask-pattern-timeout-warning = lightweight
+ }
+
+ trace {
+ join-remote-parents-with-same-span-id = yes
+ }
+
+ system-metrics {
+ host {
+ enabled = no
+ enabled = ${?SIGAR_SYSTEM_METRICS}
+ }
+ jvm {
+ enabled = no
+ enabled = ${?JVM_SYSTEM_METRICS}
+ }
+ }
+
+}
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
index c1339c7b2b5e52cf61c7bb41bb7b3ba59c451460..659940446830b456353b9f8510ff4f1428fcad39 100644
--- a/src/main/resources/log4j2.xml
+++ b/src/main/resources/log4j2.xml
@@ -10,25 +10,25 @@
<Root level="DEBUG">
<AppenderRef ref="Console"/>
</Root>
- <Logger name="akka.actor.LocalActorRefProvider(akka://woken)" level="info">
+ <Logger name="akka.actor.LocalActorRefProvider(akka://woken)" level="INFO">
<AppenderRef ref="Console"/>
</Logger>
- <Logger name="akka.cluster" level="info">
+ <Logger name="akka.cluster" level="${sys:AKKA_CLUSTER_LOG_LEVEL:-INFO}">
<AppenderRef ref="Console"/>
</Logger>
- <Logger name="akka.io" level="info">
+ <Logger name="akka.io" level="INFO">
<AppenderRef ref="Console"/>
</Logger>
- <Logger name="akka.http.impl" level="info">
+ <Logger name="akka.http.impl" level="INFO">
<AppenderRef ref="Console"/>
</Logger>
- <Logger name="akka.remote.artery.compress" level="info">
+ <Logger name="akka.remote.artery.compress" level="${sys:AKKA_CLUSTER_LOG_LEVEL:-INFO}">
<AppenderRef ref="Console"/>
</Logger>
- <Logger name="akka.remote.artery.tcp" level="info">
+ <Logger name="akka.remote.artery.tcp" level="${sys:AKKA_CLUSTER_LOG_LEVEL:-INFO}">
<AppenderRef ref="Console"/>
</Logger>
- <Logger name="akka.stream.impl" level="info">
+ <Logger name="akka.stream.impl" level="INFO">
<AppenderRef ref="Console"/>
</Logger>
</Loggers>
diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf
new file mode 100644
index 0000000000000000000000000000000000000000..c6ce4a9034d3dcca6d4d801997217c78b775684b
--- /dev/null
+++ b/src/main/resources/reference.conf
@@ -0,0 +1,12 @@
+
+app {
+ clusterSystemName = ${clustering.cluster.name}
+}
+
+# Merged with defaults in woken-messages/reference.conf
+clustering {
+ ip = "127.0.0.1"
+ ip = ${?CLUSTER_IP}
+ port = 4489
+ port = ${?CLUSTER_PORT}
+}