Make app boot without Redis: gate Valkey beans at build time, disable redis health, default OIDC off
This commit is contained in:
@@ -50,6 +50,14 @@ quarkus.http.so-reuse-port=false
|
||||
# - spring.web.resources.mime-mappings.webmanifest=application/manifest+json
|
||||
# - server.servlet.session.tracking-modes=cookie (configure on quarkus-undertow)
|
||||
|
||||
# ---- OIDC / OAuth2 login -----------------------------------------------------------------------
|
||||
# The quarkus-oidc extension is on the classpath for OAuth2/OIDC login, but it FAILS STARTUP if
|
||||
# enabled without quarkus.oidc.auth-server-url. Under Spring, OAuth2 login was activated only when
|
||||
# the operator configured a provider; the default (and the login-disabled / ultra-lite deployment)
|
||||
# ran with no OIDC at all. Mirror that: OIDC is off by default and an OAuth2 deployment re-enables
|
||||
# it by setting quarkus.oidc.enabled=true plus quarkus.oidc.auth-server-url/client-id/... .
|
||||
quarkus.oidc.enabled=false
|
||||
|
||||
# ---- Error handling (was spring.web.error.* / spring.mvc.problemdetails.enabled=false) --------
|
||||
# TODO: Migration required - GlobalExceptionHandler is an @ControllerAdvice; rewrite as JAX-RS
|
||||
# ExceptionMapper(s) producing RFC 7807 ProblemDetail responses. The Spring error-page / whitelabel
|
||||
@@ -113,6 +121,12 @@ v2=true
|
||||
# spring.config.additional-location. Quarkus uses a different config-source mechanism
|
||||
# (SmallRye Config / quarkus.config.locations). Port ConfigInitializer accordingly.
|
||||
|
||||
# ---- Redis auto-config exclusion -------------------------------------------------------------
|
||||
# ---- Redis / Valkey backplane ----------------------------------------------------------------
|
||||
# spring.autoconfigure.exclude (Redis) -> not applicable; Quarkus only wires the Redis client when
|
||||
# quarkus.redis.* is configured, so no dead localhost:6379 factory is created by default.
|
||||
# The Redis client is only used by the optional Valkey cluster backplane (cluster.enabled=true AND
|
||||
# cluster.backplane=valkey). In the default single-node deployment no quarkus.redis.hosts is set, so
|
||||
# the RedisDataSource bean is INACTIVE. The Redis readiness health check is a startup observer that
|
||||
# eagerly resolves that inactive bean and aborts boot - disable it here; a Valkey deployment that
|
||||
# configures quarkus.redis.hosts can re-enable it with quarkus.redis.health.enabled=true.
|
||||
quarkus.redis.health.enabled=false
|
||||
|
||||
+6
-7
@@ -1,5 +1,6 @@
|
||||
package stirling.software.proprietary.cluster.valkey;
|
||||
|
||||
import io.quarkus.arc.properties.IfBuildProperty;
|
||||
import io.quarkus.redis.datasource.RedisDataSource;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
@@ -10,15 +11,13 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.common.cluster.ClusterBackplane;
|
||||
import stirling.software.common.model.ApplicationProperties;
|
||||
|
||||
// Build-time gating: this bean (and its RedisDataSource dependency) is only included in the build
|
||||
// when cluster.backplane=valkey. With the default backplane (inprocess) the whole Valkey bean is
|
||||
// removed, so RedisDataSource has no consumers and Quarkus emits no eager startup observer for the
|
||||
// inactive Redis client - the in-process @DefaultBean ClusterBackplane satisfies the interface.
|
||||
@Slf4j
|
||||
@IfBuildProperty(name = "cluster.backplane", stringValue = "valkey")
|
||||
@ApplicationScoped
|
||||
// TODO: Migration required - @ConditionalOnValkeyBackplane was a Spring @ConditionalOnExpression
|
||||
// guard ("cluster.enabled=true AND cluster.backplane=valkey"). Quarkus has no runtime
|
||||
// @Conditional for beans; this bean is now always instantiated. Gate selection at runtime
|
||||
// (e.g. a ClusterBackplane producer that picks valkey vs in-process based on injected config),
|
||||
// or use @io.quarkus.arc.lookup.LookupIfProperty(name="cluster.backplane", stringValue="valkey")
|
||||
// (build-time/static only - does not also check cluster.enabled). The composite condition must be
|
||||
// re-expressed accordingly.
|
||||
public class ValkeyClusterBackplane implements ClusterBackplane {
|
||||
|
||||
@Inject ApplicationProperties applicationProperties;
|
||||
|
||||
+7
-3
@@ -6,7 +6,7 @@ import java.time.Duration;
|
||||
|
||||
import io.lettuce.core.RedisClient;
|
||||
import io.lettuce.core.RedisURI;
|
||||
import io.quarkus.arc.lookup.LookupIfProperty;
|
||||
import io.quarkus.arc.properties.IfBuildProperty;
|
||||
import io.quarkus.redis.datasource.RedisDataSource;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
@@ -53,10 +53,15 @@ import stirling.software.common.model.ApplicationProperties.Cluster;
|
||||
// so
|
||||
// the injected RedisDataSource targets the right Valkey. parseUrl/buildClientConfiguration are kept
|
||||
// to validate the URL and to drive that config mapping once it is wired.
|
||||
// Build-time gating: the whole producer class (RedisDataSource consumer + RedisClient producer) is
|
||||
// only included in the build when cluster.backplane=valkey. With the default backplane the class
|
||||
// and
|
||||
// its producers are removed, so the inactive Redis client has no consumers and no eager startup
|
||||
// observer is generated.
|
||||
@Slf4j
|
||||
@ApplicationScoped
|
||||
@RequiredArgsConstructor
|
||||
@LookupIfProperty(name = "cluster.enabled", stringValue = "true")
|
||||
@IfBuildProperty(name = "cluster.backplane", stringValue = "valkey")
|
||||
public class ValkeyConnectionConfiguration {
|
||||
|
||||
private final ApplicationProperties applicationProperties;
|
||||
@@ -298,7 +303,6 @@ public class ValkeyConnectionConfiguration {
|
||||
// RedisURI once cluster.valkey credentials handling is finalised.
|
||||
@Produces
|
||||
@Singleton
|
||||
@LookupIfProperty(name = "cluster.backplane", stringValue = "valkey")
|
||||
public RedisClient nativeRedisClient() {
|
||||
Endpoint endpoint = parseUrl(applicationProperties.getCluster().getValkey().getUrl());
|
||||
RedisURI.Builder uri =
|
||||
|
||||
+4
-3
@@ -4,7 +4,7 @@ import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import io.quarkus.arc.lookup.LookupIfProperty;
|
||||
import io.quarkus.arc.properties.IfBuildProperty;
|
||||
import io.quarkus.redis.datasource.RedisDataSource;
|
||||
import io.quarkus.redis.datasource.value.SetArgs;
|
||||
import io.quarkus.redis.datasource.value.ValueCommands;
|
||||
@@ -34,9 +34,10 @@ import stirling.software.common.cluster.DistributedLock;
|
||||
// The injected bean is now the RedisDataSource that ValkeyConnectionConfiguration produces; the Lua
|
||||
// scripts and the acquire/release/renew control flow are framework-agnostic and carry over
|
||||
// unchanged.
|
||||
// Build-time gating: included in the build only when cluster.backplane=valkey; otherwise this bean
|
||||
// (and its RedisDataSource dependency) is removed so no eager Redis startup observer is generated.
|
||||
@ApplicationScoped
|
||||
@LookupIfProperty(name = "cluster.enabled", stringValue = "true")
|
||||
@LookupIfProperty(name = "cluster.backplane", stringValue = "valkey")
|
||||
@IfBuildProperty(name = "cluster.backplane", stringValue = "valkey")
|
||||
@Slf4j
|
||||
public class ValkeyDistributedLock implements DistributedLock {
|
||||
|
||||
|
||||
+4
-4
@@ -27,10 +27,10 @@ import stirling.software.common.cluster.InstanceRegistry;
|
||||
* Valkey-backed {@link InstanceRegistry}. Each node is stored as a hash with a TTL equal to the
|
||||
* configured heartbeat TTL; the heartbeat re-arms the TTL.
|
||||
*/
|
||||
// TODO: Migration required - the original @ConditionalOnValkeyBackplane (cluster.enabled=true AND
|
||||
// cluster.backplane=valkey) was a runtime toggle. Quarkus build-time conditions (@IfBuildProfile /
|
||||
// @LookupIfProperty) cannot express this composite runtime expression. Guard producer/usage at
|
||||
// runtime via the Config values, or rework ConditionalOnValkeyBackplane into a CDI lookup guard.
|
||||
// Build-time gating: included in the build only when cluster.backplane=valkey; otherwise this bean
|
||||
// (and its RedisDataSource dependency) is removed so no eager Redis startup observer is generated
|
||||
// and the in-process @DefaultBean InstanceRegistry satisfies the interface.
|
||||
@io.quarkus.arc.properties.IfBuildProperty(name = "cluster.backplane", stringValue = "valkey")
|
||||
@ApplicationScoped
|
||||
@RequiredArgsConstructor
|
||||
public class ValkeyInstanceRegistry implements InstanceRegistry {
|
||||
|
||||
+6
@@ -44,6 +44,12 @@ import stirling.software.common.cluster.JobStoreEntry;
|
||||
// build-time condition (@io.quarkus.arc.profile.IfBuildProfile /
|
||||
// @io.quarkus.arc.lookup.LookupIfProperty) or guard bean activation at runtime. Annotation left in
|
||||
// place pending that collaborator change.
|
||||
// Build-time gating: included in the build only when cluster.backplane=valkey; otherwise this bean
|
||||
// (and its RedisDataSource dependency) is removed so no eager Redis startup observer is generated
|
||||
// and the in-process @DefaultBean JobStore satisfies the interface. @ConditionalOnValkeyBackplane
|
||||
// is
|
||||
// kept for documentation only (it does not propagate guards through Arc).
|
||||
@io.quarkus.arc.properties.IfBuildProperty(name = "cluster.backplane", stringValue = "valkey")
|
||||
@ApplicationScoped
|
||||
@ConditionalOnValkeyBackplane
|
||||
@Slf4j
|
||||
|
||||
+4
@@ -21,6 +21,10 @@ import stirling.software.common.cluster.KeyValueCache;
|
||||
// @io.quarkus.arc.lookup.LookupIfProperty
|
||||
// or @io.quarkus.arc.profile.IfBuildProfile, or a runtime guard) so Valkey beans only load when
|
||||
// cluster.enabled=true AND cluster.backplane=valkey.
|
||||
// Build-time gating: included in the build only when cluster.backplane=valkey; otherwise this bean
|
||||
// (and its RedisDataSource dependency) is removed so no eager Redis startup observer is generated
|
||||
// and the in-process @DefaultBean KeyValueCache satisfies the interface.
|
||||
@io.quarkus.arc.properties.IfBuildProperty(name = "cluster.backplane", stringValue = "valkey")
|
||||
@ApplicationScoped
|
||||
public class ValkeyKeyValueCache implements KeyValueCache {
|
||||
|
||||
|
||||
+6
-6
@@ -11,7 +11,7 @@ import io.github.bucket4j.distributed.proxy.ProxyManager;
|
||||
import io.github.bucket4j.redis.lettuce.Bucket4jLettuce;
|
||||
import io.lettuce.core.AbstractRedisClient;
|
||||
import io.lettuce.core.RedisClient;
|
||||
import io.quarkus.arc.lookup.LookupIfProperty;
|
||||
import io.quarkus.arc.properties.IfBuildProperty;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
@@ -25,13 +25,13 @@ import stirling.software.common.cluster.RateLimitStore;
|
||||
* refills continuously and enforces one global limit across nodes, with the same semantics as the
|
||||
* in-process {@code InProcessRateLimitStore} (which also uses Bucket4j).
|
||||
*/
|
||||
// @ConditionalOnValkeyBackplane is documentary only under CDI (see that annotation's javadoc);
|
||||
// the two guards below must be carried directly so the Valkey beans load only when
|
||||
// cluster.enabled=true AND cluster.backplane=valkey, otherwise the in-process @DefaultBean wins.
|
||||
// Build-time gating: included in the build only when cluster.backplane=valkey; otherwise this bean
|
||||
// (and its RedisClient dependency) is removed so no eager Redis startup observer is generated and
|
||||
// the in-process @DefaultBean RateLimitStore wins. @ConditionalOnValkeyBackplane is documentary
|
||||
// only.
|
||||
@ApplicationScoped
|
||||
@ConditionalOnValkeyBackplane
|
||||
@LookupIfProperty(name = "cluster.enabled", stringValue = "true")
|
||||
@LookupIfProperty(name = "cluster.backplane", stringValue = "valkey")
|
||||
@IfBuildProperty(name = "cluster.backplane", stringValue = "valkey")
|
||||
public class ValkeyRateLimitStore implements RateLimitStore {
|
||||
|
||||
private static final String PREFIX = "stirling:rl:";
|
||||
|
||||
Reference in New Issue
Block a user