Skip to content

Commit

Permalink
refactor: externalise some configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
kapiaszczyk committed Apr 24, 2024
1 parent 6793da3 commit aabc774
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 27 deletions.
29 changes: 20 additions & 9 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
version: '2.25.0'
name: jobboard
name: jobboard-stack

services:
# api:
# image: kapiaszczyk/jobboard-api:0.0.2
# ports:
# - "3000:3000"
# depends_on:
# - postgres
# networks:
# - postgres-network
api:
image: kapiaszczyk/job-board:0.1.0
ports:
- "8080:8080"
depends_on:
- postgres
networks:
- postgres-network
environment:
JDBC_DATABASE_USERNAME: api
JDBC_DATABASE_PASSWORD: apipassword
JDBC_DATABASE_URL: jdbc:postgresql://postgres:5432
JDBC_DATABASE_NAME: jobboard
RATE_LIMIT_BUCKET_CAPACITY: 10
RATE_LIMIT_REFILL_PERIOD_SECONDS: 1
RATE_LIMIT_REFILL_TOKENS: 1
CACHE_INITIAL_CAPACITY: 100
CACHE_MAXIMUM_SIZE: 1000
CACHE_EXPIRE_AFTER_WRITE_MINUTES: 1
postgres:
image: postgres:16
environment:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.github.benmanes.caffeine.cache.Caffeine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
Expand All @@ -17,9 +18,14 @@ public class CachingConfig {

private static final Logger LOGGER = LoggerFactory.getLogger(CachingConfig.class);

private static final int INITIAL_CAPACITY = 100;
private static final int MAXIMUM_SIZE = 500;
private static final int EXPIRE_AFTER_WRITE_MINUTES = 1;
@Value("${cache.initial.capacity}")
private int INITIAL_CAPACITY;

@Value("${cache.maximum.size}")
private int MAXIMUM_SIZE;

@Value("${cache.expire.after.write.minutes}")
private int EXPIRE_AFTER_WRITE_MINUTES;

@Bean
public CacheManager cacheManager(Caffeine caffeine) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
.requestMatchers(HttpMethod.POST, "/api/v1/companies/**").hasAnyRole("USER", "ADMIN")
.requestMatchers(HttpMethod.PUT, "/api/v1/companies/**").hasAnyRole("USER", "ADMIN")

.requestMatchers(HttpMethod.DELETE, "/api/v1/job-offers/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.DELETE, "/api/v1/companies/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.POST, "/api/v1/technologies").hasRole("ADMIN")
.requestMatchers(HttpMethod.PUT, "/api/v1/technologies/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.GET, "/api/v1/actuator/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.DELETE, "/api/v1/job-offers/**").hasAnyRole("ADMIN", "SUPER_ADMIN")
.requestMatchers(HttpMethod.DELETE, "/api/v1/companies/**").hasAnyRole("ADMIN", "SUPER_ADMIN")
.requestMatchers(HttpMethod.POST, "/api/v1/technologies").hasAnyRole("ADMIN", "SUPER_ADMIN")
.requestMatchers(HttpMethod.PUT, "/api/v1/technologies/**").hasAnyRole("ADMIN", "SUPER_ADMIN")
.requestMatchers(HttpMethod.GET, "/api/v1/actuator/**").hasAnyRole("ADMIN", "SUPER_ADMIN")

.anyRequest().authenticated()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import com.kapia.jobboard.api.data.constants.Defaults;
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.Duration;
Expand All @@ -17,25 +19,33 @@ public class RateLimitingService {

private static final Logger LOGGER = LoggerFactory.getLogger(AuthController.class);

private static final int BUCKET_CAPACITY = 100;
private static final int REFILL_TOKENS = 100;
private static final Duration REFILL_PERIOD = Duration.ofSeconds(60);
@Value("${rate.limit.bucket.capacity}")
private int BUCKET_CAPACITY;

@Value("${rate.limit.refill.period.seconds}")
private int REFILL_PERIOD_SECONDS;

@Value("${rate.limit.refill.tokens}")
private int REFILL_TOKENS;

private Duration REFILL_PERIOD;

private final Map<String, Bucket> cache = new ConcurrentHashMap<>();

public RateLimitingService() {
@PostConstruct
public void init() {
LOGGER.info("Global rate limit: {}, refilling with {} tokens per {} seconds", BUCKET_CAPACITY, REFILL_TOKENS, REFILL_PERIOD_SECONDS);

LOGGER.info("Global rate limit: {}, refilling with {} tokens per {} seconds", BUCKET_CAPACITY, REFILL_TOKENS, REFILL_PERIOD.getSeconds());
REFILL_PERIOD = Duration.ofSeconds(REFILL_PERIOD_SECONDS);

Bandwidth bandwidth = Bandwidth.builder()
.capacity(BUCKET_CAPACITY).refillGreedy(REFILL_TOKENS, REFILL_PERIOD).build();

Bucket bucket = Bucket.builder().addLimit(bandwidth).build();

cache.put(Defaults.GLOBAL_BUCKET_KEY, bucket);

}


public boolean tryConsume(String key) {
Bucket bucket = cache.computeIfAbsent(key, k -> cache.get(Defaults.GLOBAL_BUCKET_KEY));
return bucket.tryConsume(1);
Expand Down
10 changes: 9 additions & 1 deletion src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
spring.application.name=jobboard.api
### Spring Data configuration
spring.datasource.url=${JDBC_DATABASE_URL:jdbc:postgresql://localhost:5432/jobboard}
spring.datasource.url=${JDBC_DATABASE_URL:jdbc:postgresql://localhost:5432}/${JDBC_DATABASE_NAME:jobboard}
spring.datasource.username=${JDBC_DATABASE_USERNAME:api}
spring.datasource.password=${JDBC_DATABASE_PASSWORD:apipassword}
spring.datasource.driver-class-name=org.postgresql.Driver
Expand All @@ -10,6 +10,14 @@ spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
management.endpoints.web.exposure.include=index,info,health,metrics,env,caches
jwt.private.key:classpath:app.key
jwt.public.key:classpath:app.pub
### Rate limiting configuration
rate.limit.bucket.capacity=${RATE_LIMIT_BUCKET_CAPACITY:100}
rate.limit.refill.period.seconds=${RATE_LIMIT_REFILL_PERIOD_SECONDS:60}
rate.limit.refill.tokens=${RATE_LIMIT_REFILL_TOKENS:100}
cache.initial.capacity=${CACHE_INITIAL_CAPACITY:100}
cache.maximum.size=${CACHE_MAXIMUM_SIZE:500}
cache.expire.after.write.minutes=${CACHE_EXPIRE_AFTER_WRITE_MINUTES:1}
### OpenAPI configuration
api.title=Job Board API
api.version=1.0.0
api.contact=Example Company
Expand Down
12 changes: 10 additions & 2 deletions src/test/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
spring.application.name=jobboard.api
### Spring Data configuration
spring.datasource.url=${JDBC_DATABASE_URL:jdbc:postgresql://localhost:5432/jobboard}
spring.datasource.url=${JDBC_DATABASE_URL:jdbc:postgresql://localhost:5432}/${JDBC_DATABASE_NAME:jobboard}
spring.datasource.username=${JDBC_DATABASE_USERNAME:api}
spring.datasource.password=${JDBC_DATABASE_PASSWORD:apipassword}
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.open-in-view=false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
### Spring Security configuration
management.endpoints.web.exposure.include=index,info,health,metrics,env,caches
jwt.private.key:classpath:app.key
jwt.public.key:classpath:app.pub
### Rate limiting configuration
rate.limit.bucket.capacity=${RATE_LIMIT_BUCKET_CAPACITY:100}
rate.limit.refill.period.seconds=${RATE_LIMIT_REFILL_PERIOD_SECONDS:60}
rate.limit.refill.tokens=${RATE_LIMIT_REFILL_TOKENS:100}
cache.initial.capacity=${CACHE_INITIAL_CAPACITY:100}
cache.maximum.size=${CACHE_MAXIMUM_SIZE:500}
cache.expire.after.write.minutes=${CACHE_EXPIRE_AFTER_WRITE_MINUTES:1}
### OpenAPI configuration
api.title=Job Board API
api.version=1.0.0
api.contact=Example Company
Expand Down

0 comments on commit aabc774

Please sign in to comment.