Releases: riido-git/locksmith
v3.0.1
v3.0.1
Fixed
- Propagate
InterruptedExceptionfrom user methods inside@DistributedLock,@DistributedSemaphore, and template callbacks instead of silently swallowing it - Record rate-limit execution time metrics even when the method throws (wrap with try-finally in
RateLimitAspectandLocksmithRateLimitTemplate) - Only warn about
onLeaseExpiredwhenTHROW_EXCEPTIONis used withautoRenew, not for the defaultLOG_WARNINGvalue - Log full exception stack traces in semaphore permit release instead of just the message
- Wrap
DurationResolverparse errors with helpful context about the invalid input and expected formats
Changed
- Document SpEL expression cache bounding semantics in
SpELKeyResolver
Upgrade Guide
Update your dependency version:
<dependency>
<groupId>in.riido</groupId>
<artifactId>locksmith-spring-boot-starter</artifactId>
<version>3.0.1</version>
</dependency>Full Changelog: v3.0.0...v3.0.1
v3.0.0
v3.0.0
Added
-
Distributed Rate Limiting - New
@RateLimitannotation for controlling request throughput across distributed systems (#44, #7)- Configurable
permitsandinterval(e.g., 100 requests per minute) - Support for
OVERALL(shared) andPER_CLIENT(per Redisson instance) rate types viaRateTypeenum SKIP_IMMEDIATELYandWAIT_AND_SKIPacquisition modesRateLimitSkipHandlerinterface withRateLimitThrowExceptionHandlerandRateLimitReturnDefaultHandlerbuilt-in handlersRateLimitContextrecord for handler contextRateLimitExceededExceptionfor when rate limit is exceededLocksmithRateLimitTemplatefor programmatic rate limiting with fluent builderRateLimitCallbackfunctional interfaceRateLimitMetrics- Micrometer metrics integration (opt-in vialocksmith.rate-limit.metrics-enabled)- SpEL expression support for dynamic keys
- Configurable
-
Enabled Property - Conditionally disable lock, semaphore, and rate-limit components
locksmith.lock.enabled(default: true)locksmith.semaphore.enabled(default: true)locksmith.rate-limit.enabled(default: true)- Uses
@ConditionalOnPropertyto conditionally create aspects and templates
Changed
- Thread safety documentation added to Context records clarifying that args arrays are read-only by convention
Dependencies
- Bumped Redisson from 4.1.0 to 4.2.0
- Bumped maven-compiler-plugin from 3.14.1 to 3.15.0
Upgrade Guide
Update your dependency version:
<dependency>
<groupId>in.riido</groupId>
<artifactId>locksmith-spring-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>New Rate Limiting Feature
Use the new @RateLimit annotation for throughput control:
// 100 requests per minute
@RateLimit(key = "heavy-api", permits = 100, interval = "1m")
public Response heavyOperation() {
return processRequest();
}
// Per-user rate limiting with SpEL
@RateLimit(key = "#{#userId}", permits = 60, interval = "1m")
public Response userRequest(String userId) {
return processRequest();
}Or use the programmatic template:
@Service
public class MyService {
private final LocksmithRateLimitTemplate rateLimitTemplate;
public String example() throws Exception {
return rateLimitTemplate.executeWithRateLimit("api", () -> {
return "executed";
});
}
public void builderExample() throws Exception {
rateLimitTemplate.forKey("api")
.permits(100)
.interval(Duration.ofMinutes(1))
.rateType(RateType.PER_CLIENT)
.execute(() -> doWork());
}
}Disable Components
locksmith:
lock:
enabled: false # Disable distributed locks
semaphore:
enabled: true
rate-limit:
enabled: trueFull Changelog: v2.1.0...v3.0.0
v2.1.0
v2.1.0
Added
-
Micrometer Metrics Integration - Optional observability for lock and semaphore operations (#30)
LockMetricswith counters, timers, and gauges for lock operationsSemaphoreMetricswith parallel metrics for semaphore operationsLocksmithMetricsAutoConfigurationfor conditional bean creation- Metrics are opt-in via
locksmith.lock.metrics-enabledandlocksmith.semaphore.metrics-enabledproperties - Graceful degradation when Micrometer is not on classpath
-
Programmatic Templates - Alternative to annotations for lock and semaphore operations (#42)
LocksmithLockTemplatefor programmatic lock operations with fluent builder patternLocksmithSemaphoreTemplatefor programmatic semaphore operations with builder patternLockCallbackandSemaphoreCallbackfunctional interfaces- Support for auto-renew, custom timing, and all lock types
Lock Metrics
| Metric | Type | Description |
|---|---|---|
locksmith.lock.acquired |
Counter | Successful lock acquisitions |
locksmith.lock.skipped |
Counter | Skipped acquisitions (tagged by reason) |
locksmith.lock.lease.expired |
Counter | Lease expirations detected |
locksmith.lock.acquisition.time |
Timer | Time to acquire lock |
locksmith.lock.held.time |
Timer | Duration lock was held |
locksmith.lock.autorenew.active |
Gauge | Active auto-renewed locks |
Semaphore Metrics
| Metric | Type | Description |
|---|---|---|
locksmith.semaphore.acquired |
Counter | Successful permit acquisitions |
locksmith.semaphore.skipped |
Counter | Skipped acquisitions (tagged by reason) |
locksmith.semaphore.lease.expired |
Counter | Lease expirations detected |
locksmith.semaphore.acquisition.time |
Timer | Time to acquire permit |
locksmith.semaphore.held.time |
Timer | Duration permit was held |
Fixed
- Semaphore permit consistency validation in
LocksmithSemaphoreTemplate - Metrics skip reason logic using explicit mode instead of waitTime proxy
LockOperationBuildernow warns whenleaseTime()overridesautoRenew()
Upgrade Guide
Update your dependency version:
<dependency>
<groupId>in.riido</groupId>
<artifactId>locksmith-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>Enable Metrics
locksmith:
lock:
metrics-enabled: true
semaphore:
metrics-enabled: trueProgrammatic Templates
@Service
public class MyService {
private final LocksmithLockTemplate lockTemplate;
public MyService(LocksmithLockTemplate lockTemplate) {
this.lockTemplate = lockTemplate;
}
public String example() throws Exception {
return lockTemplate.executeWithLock("my-key", () -> {
return "executed";
});
}
public void builderExample() throws Exception {
lockTemplate.forKey("my-key")
.waitTime(Duration.ofSeconds(5))
.autoRenew()
.execute(() -> doWork());
}
}Full Changelog: v2.0.0...v2.1.0
v2.0.0
v2.0.0
Added
- Distributed Semaphores - New
@DistributedSemaphoreannotation for permit-based concurrency control (#8) SemaphoreSkipHandlerinterface for custom semaphore skip behaviorSemaphoreThrowExceptionHandlerandSemaphoreReturnDefaultHandlerbuilt-in handlersSemaphoreContextrecord for handler contextSemaphoreNotAcquiredExceptionandSemaphoreLeaseExpiredExceptionexceptions- Spring bean dependency injection support for skip handlers - handlers can now be Spring
@Componentbeans with@Autowireddependencies DefaultValueResolverutility for shared default value resolutionSpELKeyResolverandDurationResolvershared utilities
Changed
- Handler resolution now checks Spring ApplicationContext first, falls back to reflection
- Extracted common utilities to
supportpackage - Improved handler caching with instance-level cache per aspect
Upgrade Guide
Update your dependency version:
<dependency>
<groupId>in.riido</groupId>
<artifactId>locksmith-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>New Semaphore Feature
Use the new @DistributedSemaphore annotation for permit-based concurrency control:
@DistributedSemaphore(key = "api-pool", permits = 10, leaseTime = "5m")
public void callExternalApi() {
// Only 10 concurrent executions allowed
}Handler Dependency Injection
Skip handlers can now be Spring beans with injected dependencies:
@Component
public class AlertingSkipHandler implements LockSkipHandler {
private final AlertService alertService;
public AlertingSkipHandler(AlertService alertService) {
this.alertService = alertService;
}
@Override
public Object handle(LockContext context) {
alertService.sendAlert("Lock failed: " + context.lockKey());
return null;
}
}
// Usage
@DistributedLock(key = "my-task", skipHandler = AlertingSkipHandler.class)
public void myTask() { }Full Changelog: v1.4.3...v2.0.0
v1.4.3
Added
- Check
isHeldByCurrentThread()before unlocking with warning log for expired locks (#36)
Changed
- Improved virtual thread compatibility with better lock ownership verification (#36)
Upgrade Guide
Update your dependency version:
<dependency>
<groupId>in.riido</groupId>
<artifactId>locksmith-spring-boot-starter</artifactId>
<version>1.4.3</version>
</dependency>Full Changelog: v1.4.2...v1.4.3
v1.4.2
Added
- Logging of Redisson and Spring Boot versions during initialization
Upgrade Guide
Update your dependency version:
<dependency>
<groupId>in.riido</groupId>
<artifactId>locksmith-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>Full Changelog: v1.4.1...v1.4.2
v1.4.1
Added
- SpEL expression caching using ConcurrentHashMap (#34)
Performance
- 43% reduction in P99 latency
- 75% reduction in throughput variation
- 17% increase in concurrent throughput
- 14% reduction in CPU utilization
Changed
- Improved CI/CD pipeline with Java 17, 21, and 25 matrix testing
- Optimized test execution by excluding performance tests from CI
Upgrade Guide
Update your dependency version:
<dependency>
<groupId>in.riido</groupId>
<artifactId>locksmith-spring-boot-starter</artifactId>
<version>1.4.1</version>
</dependency>Full Changelog: v1.4.0...v1.4.1
v1.4.0
Breaking Changes
- SpEL expressions now require
#{...}wrapper syntax - change#userIdto#{#userId}(#33) - Literal keys can now contain
#character (e.g.,order#123)
Added
- Handler instance caching for better performance (#32)
- Debug mode configuration:
locksmith.debug=true - Comprehensive SpEL test coverage (38 tests)
Changed
- Removed explicit version specs for Spring Boot and SLF4J
- Improved Docker availability detection in tests
Upgrade Guide
Update your dependency version:
<dependency>
<groupId>in.riido</groupId>
<artifactId>locksmith-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>#{...} wrapper syntax.
Full Changelog: v1.3.1...v1.4.0
v1.3.1
Added
- Virtual thread integration tests for Java 21+ (10 test cases)
- Comprehensive test coverage for concurrent access and stress scenarios (#29)
Fixed
- Javadoc warnings in LockContext compact constructor
Dependencies
- Updated testcontainers to Spring Boot managed versions
- Bumped actions/checkout from 4 to 6
- Bumped actions/setup-java from 4 to 5
- Bumped actions/upload-artifact from 4 to 6
Upgrade Guide
Update your dependency version:
<dependency>
<groupId>in.riido</groupId>
<artifactId>locksmith-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>Full Changelog: v1.3.0...v1.3.1
v1.3.0
Added
- Auto-renew lease time support using Redisson watchdog mechanism (#20, #21)
- Input validation for LockContext with null checks (#15, #19)
Fixed
- Virtual thread compatibility by removing
isHeldByCurrentThread()check to prevent lock leaks (#22, #23)
Upgrade Guide
Update your dependency version:
<dependency>
<groupId>in.riido</groupId>
<artifactId>locksmith-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>Full Changelog: v1.2.2...v1.3.0