failover
Used in:
components
- OverviewOverview
- VersionsVersions
- DependentsDependents
- DependenciesDependencies
<dependency>
<groupId>com.societegenerale.failover</groupId>
<artifactId>failover</artifactId>
<version>3.0.0</version>
</dependency><?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.societegenerale.failover</groupId>
<artifactId>failover</artifactId>
<version>3.0.0</version>
<packaging>pom</packaging>
<name>failover</name>
<description>A library for managing failover</description>
<url>https://github.com/societe-generale/failover</url>
<properties>
<java.version>21</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<!-- JPMS automatic module name; overridden per module (audit A-1 / Phase 4.2). -->
<automatic.module.name>com.societegenerale.failover</automatic.module.name>
<jspecify.version>1.0.0</jspecify.version>
<!-- SPRING BOOT VERSION -->
<spring-boot.version>4.0.6</spring-boot.version>
<spring-cloud.version>2025.1.1</spring-cloud.version>
<!-- Plugin -->
<maven-failsafe-plugin.version>3.5.6</maven-failsafe-plugin.version>
<maven-scm-plugin.version>2.2.1</maven-scm-plugin.version>
<maven-release-plugin.version>3.3.1</maven-release-plugin.version>
<maven-source-plugin.version>3.4.0</maven-source-plugin.version>
<!-- Maven Central publishing. Replaces the EOL nexus-staging-maven-plugin: OSSRH
(s01.oss.sonatype.org) is decommissioned, all publishing now goes via the Central Portal. -->
<central-publishing-maven-plugin.version>0.11.0</central-publishing-maven-plugin.version>
<maven-gpg-plugin.version>3.2.8</maven-gpg-plugin.version>
<maven-enforcer-plugin.version>3.6.3</maven-enforcer-plugin.version>
<maven-surefire-plugin.version>3.5.6</maven-surefire-plugin.version>
<jacoco.version>0.8.15</jacoco.version>
<sonar.language>java</sonar.language>
<sonar-maven-plugin.version>5.7.0.6970</sonar-maven-plugin.version>
<maven-dependency-plugin.version>3.11.0</maven-dependency-plugin.version>
<maven-jar-plugin.version>3.5.0</maven-jar-plugin.version>
<maven-javadoc-plugin.version>3.12.0</maven-javadoc-plugin.version>
<maven-compiler-plugin.version>3.15.0</maven-compiler-plugin.version>
<lombok.version>1.18.46</lombok.version>
<!-- Phase 3 test-depth tooling (JDBC drivers are managed by spring-boot-dependencies) -->
<testcontainers.version>1.21.4</testcontainers.version>
<archunit.version>1.3.0</archunit.version>
<pitest.version>1.25.5</pitest.version>
<pitest-junit5.version>1.2.3</pitest-junit5.version>
<!-- JMH micro-benchmark harness (profile-gated `-Pbenchmark`; excluded from the default build). -->
<jmh.version>1.37</jmh.version>
<!-- PIT runs only where overridden to false (failover-core). Default skips it so `-am`
reactor builds don't run PIT on modules with no matching target classes (which would
fail with "No mutations found" under failWhenNoMutations=true). -->
<pitest.skip>true</pitest.skip>
<rewrite-maven-plugin.version>6.39.0</rewrite-maven-plugin.version>
<rewrite-spring.version>6.30.4</rewrite-spring.version>
<rewrite-migrate-java.version>3.7.0</rewrite-migrate-java.version>
<sonar.java.libraries>target/dependency/*.jar</sonar.java.libraries>
<project.coverage.directory>${project.build.directory}/coverage-results</project.coverage.directory>
<sonar.coverage.jacoco.xmlReportPaths>../failover-test-report/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
<!-- Security CVE patches — explicit overrides, no spring-boot-parent -->
<tomcat.embed.version>11.0.22</tomcat.embed.version>
<postgresql.override.version>42.7.12</postgresql.override.version>
<jackson-databind-2.version>2.22.0</jackson-databind-2.version>
<jackson-databind-3.version>3.1.5</jackson-databind-3.version>
<bouncycastle.version>1.85</bouncycastle.version>
<commons-compress.version>1.26.0</commons-compress.version>
</properties>
<developers>
<developer>
<id>anandmnair</id>
<name>Anand Manissery</name>
<email>anand.manissery@gmail.com</email>
</developer>
</developers>
<licenses>
<license>
<name>Apache 2</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.html</url>
<distribution>repo</distribution>
</license>
</licenses>
<issueManagement>
<url>https://github.com/societe-generale/failover/issues</url>
<system>GitHub</system>
</issueManagement>
<scm>
<url>https://github.com/societe-generale/failover</url>
<connection>scm:git:git@github.com:societe-generale/failover.git</connection>
<developerConnection>scm:git:git@github.com:societe-generale/failover.git</developerConnection>
<tag>failover_3.0.0</tag>
</scm>
<!-- No <distributionManagement>: publishing goes through the Central Portal, whose
central-publishing-maven-plugin (see the 'makeRelease' profile) supplies the upload target
itself. The legacy OSSRH hosts (oss.sonatype.org / s01.oss.sonatype.org) are decommissioned
and answer HTTP 402 — deploying to them can no longer succeed. -->
<modules>
<module>failover-domain</module>
<module>failover-core</module>
<module>failover-scanner</module>
<module>failover-observable-micrometer</module>
<module>failover-observable-metrics</module>
<module>failover-store-inmemory</module>
<module>failover-store-caffeine</module>
<module>failover-store-jdbc</module>
<module>failover-store-async</module>
<module>failover-store-multitenant</module>
<module>failover-aspect</module>
<module>failover-scheduler</module>
<module>failover-lookup</module>
<module>failover-execution-resilience</module>
<module>failover-spring-boot-autoconfigure</module>
<module>failover-spring-boot-starter</module>
<module>failover-dashboard</module>
<module>failover-dashboard-snapshotstore-jdbc</module>
<module>failover-dashboard-spring-boot-starter</module>
<module>failover-test-report</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
<version>${jspecify.version}</version>
</dependency>
<!-- CVE patches: explicit overrides take precedence over imported BOMs -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>${tomcat.embed.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>${tomcat.embed.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>${tomcat.embed.version}</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgresql.override.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind-2.version}</version>
</dependency>
<dependency>
<groupId>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind-3.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>${commons-compress.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
<version>${jspecify.version}</version>
</dependency>
<!-- TEST -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven-failsafe-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- @{argLine} is set by jacoco:prepare-agent-integration; keep it first so IT coverage is recorded. -->
<!-- Raise the Spring TestContext cache above its default (32): the *IT classes here span many
distinct @TestPropertySource combinations, each a unique context; below this size the cache
thrashes (evict + rebuild) mid-run instead of reusing contexts already started. -->
<argLine>@{argLine} --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED --add-opens java.base/jdk.internal.reflect=ALL-UNNAMED -Dnet.bytebuddy.experimental=true -Dspring.test.context.cache.maxSize=64</argLine>
<!-- Dialect ITs require Docker (Testcontainers); excluded from the default build, re-enabled by the 'dialect-its' profile in failover-store-jdbc. -->
<excludes>
<exclude>**/*DialectIT.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>${maven-release-plugin.version}</version>
<configuration>
<!-- No <stagingRepository>: the Central Portal plugin owns the upload target. -->
<tagNameFormat>failover_@{project.version}</tagNameFormat>
<localCheckout>true</localCheckout>
<autoVersionSubmodules>true</autoVersionSubmodules>
<pushChanges>false</pushChanges>
<useReleaseProfile>false</useReleaseProfile>
<releaseProfiles>makeRelease</releaseProfiles>
<mavenExecutorId>forked-path</mavenExecutorId>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<!-- @{argLine} is set by jacoco:prepare-agent; keep it first so coverage is recorded. -->
<!-- Same context-cache reasoning as the failsafe argLine above: many *Test classes here
(e.g. FailoverAutoConfigurationTest, FailoverStoreAutoConfigurationTest) carry distinct
@TestPropertySource combos, each a unique Spring context. -->
<argLine>@{argLine} --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED --add-opens java.base/jdk.internal.reflect=ALL-UNNAMED -Dnet.bytebuddy.experimental=true -Dspring.test.context.cache.maxSize=64</argLine>
</configuration>
</plugin>
<plugin>
<artifactId>maven-scm-plugin</artifactId>
<version>${maven-scm-plugin.version}</version>
<configuration>
<tag>${project.version}</tag>
</configuration>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>${maven-source-plugin.version}</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<version>${maven-enforcer-plugin.version}</version>
<configuration>
<rules>
<dependencyConvergence />
<!-- Only forbid SNAPSHOT dependencies for an actual release build; the reactor
modules legitimately depend on each other via the current SNAPSHOT version. -->
<requireReleaseDeps>
<onlyWhenRelease>true</onlyWhenRelease>
</requireReleaseDeps>
</rules>
<!-- Convergence violations now fail the build (was advisory) — version skew is
especially harmful for a library published to consumers. -->
<fail>true</fail>
</configuration>
<executions>
<execution>
<id>enforce-versions</id>
<goals>
<goal>enforce</goal>
</goals>
<phase>validate</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${project.coverage.directory}/jacoco-ut.exec</destFile>
</configuration>
</execution>
<execution>
<id>prepare-agent-integration</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<destFile>${project.coverage.directory}/jacoco-it.exec</destFile>
</configuration>
</execution>
<execution>
<id>merge</id>
<phase>verify</phase>
<goals>
<goal>merge</goal>
</goals>
<configuration>
<fileSets>
<fileSet>
<directory>${project.coverage.directory}</directory>
<includes>
<include>*.exec</include>
</includes>
</fileSet>
</fileSets>
<destFile>${project.coverage.directory}/aggregate.exec</destFile>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>${sonar-maven-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
<manifestEntries>
<Automatic-Module-Name>${automatic.module.name}</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>${maven-dependency-plugin.version}</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeArtifactIds>lombok</includeArtifactIds>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven-javadoc-plugin.version}</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<id>attach-javadoc</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
<execution>
<id>aggregate</id>
<goals>
<goal>aggregate</goal>
</goals>
<phase>site</phase>
<configuration>
<outputDirectory>${project.basedir}/docs/api/javadoc</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<profiles>
<profile>
<id>makeRelease</id>
<build>
<plugins>
<!--
Maven Central publishing via the Central Portal (central.sonatype.com).
Replaces nexus-staging-maven-plugin: the legacy OSSRH hosts it talked to are
decommissioned, so that plugin can no longer publish anything. extensions=true
swaps the default deploy target for the Portal upload, so no
<distributionManagement> is needed (or wanted — it would be ignored at best).
Credentials come from a <server> with id 'central' in settings.xml, holding a
Central Portal *user token* (username + password generated at
central.sonatype.com/account) — an OSSRH JIRA account or an old OSSRH token will
not authenticate. In CI, actions/setup-java writes that <server> block from the
MAVEN_USERNAME / MAVEN_PASSWORD env vars.
autoPublish=true releases the deployment once validation passes, matching the
old autoReleaseAfterClose=true behaviour. Set it to false to park the upload in
the Portal UI for a manual publish decision.
-->
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>${central-publishing-maven-plugin.version}</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
<autoPublish>true</autoPublish>
<!-- Block until Central finishes validating, so a rejected bundle fails
the workflow instead of passing green with nothing published. -->
<waitUntil>published</waitUntil>
<!--
failover-test-report is the JaCoCo coverage aggregator, not a consumable
artifact: its jar is filled by dependency:unpack-dependencies with a copy of
every other module's classes purely so the cross-module coverage gate has
something to analyse. Publishing it would ship a duplicate of the whole
library under a meaningless coordinate. Matched on plain artifactId
(PublishMojo does excludeArtifacts.contains(artifact.getArtifactId())).
-->
<excludeArtifacts>
<excludeArtifact>failover-test-report</excludeArtifact>
</excludeArtifacts>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven-source-plugin.version}</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>${maven-gpg-plugin.version}</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
<!--
No passphrase and no gpgArguments on purpose. maven-gpg-plugin 3.x reads the
passphrase from the env var named by `passphraseEnvName`, which already defaults to
MAVEN_GPG_PASSPHRASE — the variable the release workflow sets. Its GpgSigner also
emits the batch, pinentry-mode loopback and passphrase-fd flags itself, so passing
those arguments by hand only risks duplicating them.
bestPractices=true turns the plugin's "sensitive data handled badly" warnings into
hard failures, so the deprecated `passphrase` parameter (which the plugin documents
as leaking sensitive data) can never be reintroduced here unnoticed. It is a no-op
against the current configuration — purely a guardrail.
-->
<configuration>
<bestPractices>true</bestPractices>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<!--
Mutation testing (PIT) — advisory, profile-gated so the default build is unaffected.
Scoped to the failover core module boundary logic where mutation testing pays off most (audit T-4).
Run: mvn -pl failover-core -Pmutation test (report under target/pit-reports)
-->
<profile>
<id>mutation</id>
<build>
<plugins>
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>${pitest.version}</version>
<dependencies>
<dependency>
<groupId>org.pitest</groupId>
<artifactId>pitest-junit5-plugin</artifactId>
<version>${pitest-junit5.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>pit-mutation-coverage</id>
<phase>test</phase>
<goals>
<goal>mutationCoverage</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- Skip in every module except failover-core (which sets pitest.skip=false). -->
<skip>${pitest.skip}</skip>
<!--
Do NOT inherit the surefire argLine: it carries the JaCoCo javaagent and the
late-bound @{argLine} token, which the PIT minion JVM cannot resolve and which
makes it exit abnormally (UNKNOWN_ERROR). Pass only the opens PIT actually needs.
-->
<parseSurefireConfig>false</parseSurefireConfig>
<jvmArgs>
<jvmArg>--add-opens=java.base/java.lang=ALL-UNNAMED</jvmArg>
<jvmArg>--add-opens=java.base/java.lang.reflect=ALL-UNNAMED</jvmArg>
<jvmArg>-Dnet.bytebuddy.experimental=true</jvmArg>
</jvmArgs>
<targetClasses>
<param>com.societegenerale.failover.core.*</param>
</targetClasses>
<targetTests>
<param>com.societegenerale.failover.core.*</param>
</targetTests>
<!--
CI (ubuntu-latest) runs mutants on a shared, throttled runner with cold JVM
forks per minion; PIT's defaults (timeoutConst=4000ms, timeoutFactor=1.25x)
are too tight there and minions die with TIMED_OUT before running any mutant.
Local runs are unaffected — these only raise the ceiling.
-->
<timeoutConstant>12000</timeoutConstant>
<timeoutFactor>2.0</timeoutFactor>
<!-- ubuntu-latest gives 4 vCPUs; run mutants in parallel instead of PIT's single-thread default. -->
<threads>2</threads>
<!-- Mandated gate: the expiry + key logic must reach 95% mutation coverage. -->
<mutationThreshold>95</mutationThreshold>
<!-- Fail if the target globs ever match zero classes, so the 95% gate can never pass vacuously. -->
<failWhenNoMutations>true</failWhenNoMutations>
<outputFormats>
<param>HTML</param>
<param>XML</param>
</outputFormats>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>