Skip to content

Configuration

Garvit Joshi edited this page Jan 29, 2026 · 6 revisions

Configuration

Locksmith requires a Redis connection and supports customization of default behavior for locks, semaphores, and rate limiters.

Redis Connection

Locksmith uses Redisson for Redis connectivity. You must provide a RedissonClient bean:

Single Server

@Configuration
public class RedisConfig {

    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer()
              .setAddress("redis://localhost:6379")
              .setPassword("your-password")  // if required
              .setDatabase(0);
        return Redisson.create(config);
    }
}

Sentinel (High Availability)

@Configuration
public class RedisConfig {

    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSentinelServers()
              .setMasterName("mymaster")
              .addSentinelAddress(
                  "redis://sentinel1:26379",
                  "redis://sentinel2:26379",
                  "redis://sentinel3:26379"
              )
              .setPassword("your-password");
        return Redisson.create(config);
    }
}

Cluster

@Configuration
public class RedisConfig {

    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useClusterServers()
              .addNodeAddress(
                  "redis://node1:6379",
                  "redis://node2:6379",
                  "redis://node3:6379"
              )
              .setPassword("your-password");
        return Redisson.create(config);
    }
}

From YAML File

@Configuration
public class RedisConfig {

    @Bean
    public RedissonClient redissonClient() throws IOException {
        Config config = Config.fromYAML(new File("redisson.yaml"));
        return Redisson.create(config);
    }
}

redisson.yaml:

singleServerConfig:
  address: "redis://localhost:6379"
  password: null
  database: 0
  connectionMinimumIdleSize: 10
  connectionPoolSize: 64
  idleConnectionTimeout: 10000
  connectTimeout: 10000
  timeout: 3000
  retryAttempts: 3
  retryInterval: 1500

Locksmith Properties

Configure default behavior in application.properties or application.yml. Locksmith v2.0+ uses a nested structure for separate lock, semaphore, and rate limit configuration.

application.yml

locksmith:
  lock:
    enabled: true         # Enable/disable lock aspect and template
    lease-time: 10m       # Default lock duration
    wait-time: 60s        # Default wait time for WAIT_AND_SKIP mode
    key-prefix: "lock:"   # Prefix for all lock keys in Redis
    debug: false          # Enable debug logging
    metrics-enabled: false  # Enable Micrometer metrics
  semaphore:
    enabled: true         # Enable/disable semaphore aspect and template
    lease-time: 5m        # Default permit lease duration
    wait-time: 60s        # Default wait time for WAIT_AND_SKIP mode
    key-prefix: "semaphore:"  # Prefix for all semaphore keys in Redis
    debug: false          # Enable debug logging
    metrics-enabled: false  # Enable Micrometer metrics
  rate-limit:
    enabled: true         # Enable/disable rate limit aspect and template
    wait-time: 60s        # Default wait time for WAIT_AND_SKIP mode
    key-prefix: "ratelimit:"  # Prefix for all rate limit keys in Redis
    debug: false          # Enable debug logging
    metrics-enabled: false  # Enable Micrometer metrics

application.properties

# Lock configuration
locksmith.lock.enabled=true
locksmith.lock.lease-time=10m
locksmith.lock.wait-time=60s
locksmith.lock.key-prefix=lock:
locksmith.lock.debug=false
locksmith.lock.metrics-enabled=false

# Semaphore configuration
locksmith.semaphore.enabled=true
locksmith.semaphore.lease-time=5m
locksmith.semaphore.wait-time=60s
locksmith.semaphore.key-prefix=semaphore:
locksmith.semaphore.debug=false
locksmith.semaphore.metrics-enabled=false

# Rate limit configuration
locksmith.rate-limit.enabled=true
locksmith.rate-limit.wait-time=60s
locksmith.rate-limit.key-prefix=ratelimit:
locksmith.rate-limit.debug=false
locksmith.rate-limit.metrics-enabled=false

Property Reference

Lock Properties

Property Type Default Description
locksmith.lock.enabled Boolean true Enable/disable lock aspect and template. When false, @DistributedLock methods execute without acquiring locks.
locksmith.lock.lease-time Duration 10m How long a lock is held before auto-release
locksmith.lock.wait-time Duration 60s How long to wait in WAIT_AND_SKIP mode
locksmith.lock.key-prefix String lock: Prefix added to all lock keys in Redis
locksmith.lock.debug Boolean false Enable detailed debug logging
locksmith.lock.metrics-enabled Boolean false Enable Micrometer metrics for locks

Semaphore Properties

Property Type Default Description
locksmith.semaphore.enabled Boolean true Enable/disable semaphore aspect and template. When false, @DistributedSemaphore methods execute without acquiring permits.
locksmith.semaphore.lease-time Duration 5m How long a permit is held before auto-release
locksmith.semaphore.wait-time Duration 60s How long to wait in WAIT_AND_SKIP mode
locksmith.semaphore.key-prefix String semaphore: Prefix added to all semaphore keys in Redis
locksmith.semaphore.debug Boolean false Enable detailed debug logging
locksmith.semaphore.metrics-enabled Boolean false Enable Micrometer metrics for semaphores

Rate Limit Properties

Property Type Default Description
locksmith.rate-limit.enabled Boolean true Enable/disable rate limit aspect and template. When false, @RateLimit methods execute without rate limiting.
locksmith.rate-limit.wait-time Duration 60s How long to wait in WAIT_AND_SKIP mode
locksmith.rate-limit.key-prefix String ratelimit: Prefix added to all rate limit keys in Redis
locksmith.rate-limit.debug Boolean false Enable detailed debug logging
locksmith.rate-limit.metrics-enabled Boolean false Enable Micrometer metrics for rate limits

Duration Format

Locksmith supports multiple duration formats:

Simple Format

locksmith:
  lock:
    lease-time: 30s      # 30 seconds
    wait-time: 5m        # 5 minutes
  semaphore:
    lease-time: 2m       # 2 minutes
Unit Example Description
ms 500ms Milliseconds
s 30s Seconds
m 10m Minutes
h 1h Hours

ISO-8601 Format

locksmith:
  lock:
    lease-time: PT10M    # 10 minutes
    wait-time: PT30S     # 30 seconds

Per-Method Override

You can override defaults on individual methods:

Locks

// Uses global defaults
@DistributedLock(key = "task1")
public void task1() { }

// Override lease time
@DistributedLock(key = "task2", leaseTime = "30m")
public void task2() { }

// Override wait time
@DistributedLock(
    key = "task3",
    mode = AcquisitionMode.WAIT_AND_SKIP,
    waitTime = "2m"
)
public void task3() { }

Semaphores

// Uses global defaults
@DistributedSemaphore(key = "pool1", permits = 5)
public void pool1() { }

// Override lease time
@DistributedSemaphore(key = "pool2", permits = 10, leaseTime = "30m")
public void pool2() { }

// Override wait time
@DistributedSemaphore(
    key = "pool3",
    permits = 3,
    mode = AcquisitionMode.WAIT_AND_SKIP,
    waitTime = "2m"
)
public void pool3() { }

Rate Limits

// 10 permits per second (default)
@RateLimit(key = "api1")
public void api1() { }

// 100 permits per minute
@RateLimit(key = "api2", permits = 100, interval = "1m")
public void api2() { }

// Per-client rate limiting with wait
@RateLimit(
    key = "api3",
    permits = 50,
    interval = "1m",
    type = RateType.PER_CLIENT,
    mode = AcquisitionMode.WAIT_AND_SKIP,
    waitTime = "5s"
)
public void api3() { }

Key Prefix Strategy

Prefixes are prepended to all keys:

locksmith:
  lock:
    key-prefix: "myapp:lock:"
  semaphore:
    key-prefix: "myapp:sem:"
  rate-limit:
    key-prefix: "myapp:rl:"

With this config:

  • @DistributedLock(key = "task") → Redis key: myapp:lock:task
  • @DistributedSemaphore(key = "pool", permits = 5) → Redis key: myapp:sem:pool
  • @RateLimit(key = "api") → Redis key: myapp:rl:api

Multi-Environment Setup

Use different prefixes per environment to prevent conflicts:

# application-dev.yml
locksmith:
  lock:
    key-prefix: "dev:lock:"
  semaphore:
    key-prefix: "dev:sem:"
  rate-limit:
    key-prefix: "dev:rl:"

# application-prod.yml
locksmith:
  lock:
    key-prefix: "prod:lock:"
  semaphore:
    key-prefix: "prod:sem:"
  rate-limit:
    key-prefix: "prod:rl:"

Redisson Watchdog Configuration

For auto-renew feature (locks only), you can configure Redisson's watchdog:

@Bean
public RedissonClient redissonClient() {
    Config config = new Config();
    config.setLockWatchdogTimeout(30000);  // 30 seconds (default)
    config.useSingleServer()
          .setAddress("redis://localhost:6379");
    return Redisson.create(config);
}

The watchdog renews locks every lockWatchdogTimeout / 3 (~10 seconds by default).

Debug Mode

Enable debug logging for detailed operation information:

locksmith:
  lock:
    debug: true
  semaphore:
    debug: true
  rate-limit:
    debug: true

Debug output includes:

  • Key resolution details
  • Acquisition attempts and results
  • Timing information
  • Release confirmations

You can also enable Spring's debug logging:

logging:
  level:
    in.riido.locksmith: DEBUG
    org.redisson: DEBUG

Disabling Features

You can disable individual features without removing annotations from your code. When disabled, annotated methods execute normally without acquiring locks, semaphore permits, or checking rate limits.

Disable All Locks

locksmith:
  lock:
    enabled: false  # @DistributedLock annotations have no effect

Disable All Semaphores

locksmith:
  semaphore:
    enabled: false  # @DistributedSemaphore annotations have no effect

Disable All Rate Limits

locksmith:
  rate-limit:
    enabled: false  # @RateLimit annotations have no effect

Use Cases for Disabling

  • Local development: Avoid needing Redis during development
  • Testing: Run integration tests without distributed coordination
  • Troubleshooting: Isolate issues by temporarily disabling features
  • Gradual rollout: Enable features selectively per environment

Per-Environment Example

# application-dev.yml - No Redis needed for local development
locksmith:
  lock:
    enabled: false
  semaphore:
    enabled: false
  rate-limit:
    enabled: false

# application-prod.yml - Full distributed coordination
locksmith:
  lock:
    enabled: true
  semaphore:
    enabled: true
  rate-limit:
    enabled: true

Validation

Locksmith validates configuration at startup:

Property Validation Fallback
lease-time Must be positive 10m (locks), 5m (semaphores)
wait-time Must be non-negative 60 seconds
key-prefix Must not be blank lock: or semaphore:
debug Must be boolean false

Invalid values are logged as warnings and replaced with defaults:

WARN  Invalid leaseTime: PT0S. Using default: PT10M

Complete Example

# application.yml
spring:
  application:
    name: my-service

locksmith:
  lock:
    lease-time: 15m
    wait-time: 30s
    key-prefix: "my-service:lock:"
    debug: false
    metrics-enabled: true
  semaphore:
    lease-time: 10m
    wait-time: 30s
    key-prefix: "my-service:sem:"
    debug: false
    metrics-enabled: true
  rate-limit:
    wait-time: 30s
    key-prefix: "my-service:rl:"
    debug: false
    metrics-enabled: true

logging:
  level:
    in.riido.locksmith: INFO
@Configuration
public class RedisConfig {

    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.setLockWatchdogTimeout(30000);
        config.useSingleServer()
              .setAddress("redis://localhost:6379")
              .setConnectionPoolSize(64)
              .setConnectionMinimumIdleSize(10);
        return Redisson.create(config);
    }
}

Migration from v1.x

If upgrading from Locksmith v1.x, update your configuration:

Before (v1.x):

locksmith:
  lease-time: 10m
  wait-time: 60s
  key-prefix: "lock:"

After (v2.0):

locksmith:
  lock:
    lease-time: 10m
    wait-time: 60s
    key-prefix: "lock:"
  semaphore:
    lease-time: 5m
    wait-time: 60s
    key-prefix: "semaphore:"

Next Steps

Clone this wiki locally