Performance tuning done

This commit is contained in:
2026-07-23 11:53:40 +05:30
parent 4cbd510b85
commit dcb40473da
2155 changed files with 652296 additions and 230 deletions

View File

@@ -0,0 +1,14 @@
package com.cygnus.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
@SpringBootApplication
@ConfigurationPropertiesScan
public class CygnusCloudServiceApplication {
public static void main(String[] args) {
SpringApplication.run(CygnusCloudServiceApplication.class, args);
}
}

View File

@@ -0,0 +1,9 @@
package com.cygnus.cloud.cache;
import java.time.Duration;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("cygnus.cache")
public record CacheProperties(String keyPrefix, Duration defaultTtl) {
}

View File

@@ -0,0 +1,44 @@
package com.cygnus.cloud.cache;
import java.time.Duration;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
@Service
public class ReactiveCacheService {
private final ReactiveStringRedisTemplate redis;
private final CacheProperties properties;
public ReactiveCacheService(ReactiveStringRedisTemplate redis, CacheProperties properties) {
this.redis = redis;
this.properties = properties;
}
public Mono<String> get(String namespace, String key) {
return redis.opsForValue().get(cacheKey(namespace, key));
}
public Mono<Boolean> put(String namespace, String key, String value) {
return put(namespace, key, value, properties.defaultTtl());
}
public Mono<Boolean> put(String namespace, String key, String value, Duration ttl) {
return redis.opsForValue().set(cacheKey(namespace, key), value, ttl);
}
public Mono<Boolean> putIfAbsent(String namespace, String key, String value, Duration ttl) {
return redis.opsForValue().setIfAbsent(cacheKey(namespace, key), value, ttl);
}
public Mono<Boolean> evict(String namespace, String key) {
return redis.delete(cacheKey(namespace, key)).map(deleted -> deleted > 0);
}
private String cacheKey(String namespace, String key) {
return properties.keyPrefix() + ':' + namespace + ':' + key;
}
}

View File

@@ -0,0 +1,18 @@
package com.cygnus.cloud.database;
import java.time.Duration;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("cygnus.database")
public record DatabaseProperties(
String host,
int port,
String database,
String username,
String password,
boolean ssl,
Duration connectTimeout,
int poolSize,
int poolWaitQueueSize) {
}

View File

@@ -0,0 +1,32 @@
package com.cygnus.cloud.database;
import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.RowSet;
import io.vertx.sqlclient.Tuple;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
/**
* Reactor boundary around the Vert.x PostgreSQL pool. Feature repositories
* should use parameterized SQL and pass values through {@link Tuple}.
*/
@Service
public class ReactiveDatabaseClient {
private final Pool pool;
public ReactiveDatabaseClient(Pool pool) {
this.pool = pool;
}
public Mono<RowSet<Row>> query(String sql) {
return Mono.fromCompletionStage(() -> pool.query(sql).execute().toCompletionStage());
}
public Mono<RowSet<Row>> preparedQuery(String sql, Tuple parameters) {
return Mono.fromCompletionStage(
() -> pool.preparedQuery(sql).execute(parameters).toCompletionStage());
}
}

View File

@@ -0,0 +1,44 @@
package com.cygnus.cloud.database;
import io.vertx.core.Vertx;
import io.vertx.pgclient.PgConnectOptions;
import io.vertx.pgclient.PgBuilder;
import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.PoolOptions;
import java.util.concurrent.TimeUnit;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class VertxDatabaseConfiguration {
@Bean(destroyMethod = "close")
Vertx vertx() {
return Vertx.vertx();
}
@Bean(destroyMethod = "close")
Pool postgresPool(Vertx vertx, DatabaseProperties properties) {
PgConnectOptions connection = new PgConnectOptions()
.setHost(properties.host())
.setPort(properties.port())
.setDatabase(properties.database())
.setUser(properties.username())
.setPassword(properties.password())
.setSslMode(properties.ssl()
? io.vertx.pgclient.SslMode.REQUIRE
: io.vertx.pgclient.SslMode.DISABLE);
PoolOptions pool = new PoolOptions()
.setMaxSize(properties.poolSize())
.setMaxWaitQueueSize(properties.poolWaitQueueSize())
.setConnectionTimeout(Math.toIntExact(properties.connectTimeout().toMillis()))
.setConnectionTimeoutUnit(TimeUnit.MILLISECONDS);
return PgBuilder.pool()
.using(vertx)
.connectingTo(connection)
.with(pool)
.build();
}
}

View File

@@ -0,0 +1,25 @@
package com.cygnus.cloud.security;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
import org.springframework.security.oauth2.jwt.Jwt;
final class AudienceValidator implements OAuth2TokenValidator<Jwt> {
private static final OAuth2Error INVALID_AUDIENCE =
new OAuth2Error("invalid_token", "Required token audience is missing", null);
private final String audience;
AudienceValidator(String audience) {
this.audience = audience;
}
@Override
public OAuth2TokenValidatorResult validate(Jwt jwt) {
return jwt.getAudience().contains(audience)
? OAuth2TokenValidatorResult.success()
: OAuth2TokenValidatorResult.failure(INVALID_AUDIENCE);
}
}

View File

@@ -0,0 +1,48 @@
package com.cygnus.cloud.security;
import static org.springframework.security.config.Customizer.withDefaults;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtValidators;
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.security.web.server.SecurityWebFilterChain;
@Configuration
public class CloudSecurityConfiguration {
@Bean
SecurityWebFilterChain cloudSecurityFilterChain(
ServerHttpSecurity http,
CommunicationSecurityProperties properties) {
http.csrf(ServerHttpSecurity.CsrfSpec::disable);
if (!properties.enabled()) {
return http.authorizeExchange(exchange -> exchange.anyExchange().permitAll()).build();
}
return http
.authorizeExchange(exchange -> exchange
.pathMatchers("/actuator/health", "/actuator/info").permitAll()
.anyExchange().authenticated())
.oauth2ResourceServer(resourceServer -> resourceServer.jwt(withDefaults()))
.build();
}
@Bean
@ConditionalOnProperty(name = "cygnus.security.enabled", havingValue = "true")
ReactiveJwtDecoder reactiveJwtDecoder(CommunicationSecurityProperties properties) {
NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder
.withIssuerLocation(properties.issuerUri())
.build();
decoder.setJwtValidator(new DelegatingOAuth2TokenValidator<Jwt>(
JwtValidators.createDefaultWithIssuer(properties.issuerUri()),
new AudienceValidator(properties.audience())));
return decoder;
}
}

View File

@@ -0,0 +1,14 @@
package com.cygnus.cloud.security;
import java.time.Duration;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("cygnus.security")
public record CommunicationSecurityProperties(
boolean enabled,
String issuerUri,
String audience,
Duration assertionTtl,
Duration accessTokenTtl) {
}

View File

@@ -0,0 +1,24 @@
package com.cygnus.cloud.security;
import java.time.Duration;
import com.cygnus.cloud.cache.ReactiveCacheService;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
@Service
public class JwtReplayProtectionService {
private static final String NAMESPACE = "jwt-jti";
private final ReactiveCacheService cache;
public JwtReplayProtectionService(ReactiveCacheService cache) {
this.cache = cache;
}
public Mono<Boolean> claim(String jwtId, Duration remainingLifetime) {
return cache.putIfAbsent(NAMESPACE, jwtId, "used", remainingLifetime);
}
}

View File

@@ -0,0 +1,15 @@
package com.cygnus.cloud.system;
import java.time.Clock;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SystemConfiguration {
@Bean
Clock systemClock() {
return Clock.systemUTC();
}
}

View File

@@ -0,0 +1,29 @@
package com.cygnus.cloud.system;
import java.time.Clock;
import java.time.Instant;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api/v1/system")
public class SystemInfoController {
private final Clock clock;
public SystemInfoController(Clock clock) {
this.clock = clock;
}
@GetMapping("/info")
public Mono<SystemInfoResponse> info() {
return Mono.just(new SystemInfoResponse(
"cygnus-cloud-service",
"1.0.0-SNAPSHOT",
Instant.now(clock)));
}
}

View File

@@ -0,0 +1,6 @@
package com.cygnus.cloud.system;
import java.time.Instant;
public record SystemInfoResponse(String service, String version, Instant timestamp) {
}