{"id":35091395,"url":"https://github.com/riido-git/locksmith","last_synced_at":"2026-02-06T21:04:27.356Z","repository":{"id":330070645,"uuid":"1120074521","full_name":"riido-git/locksmith","owner":"riido-git","description":"A Spring Boot starter for Redis-based distributed locking using annotations. Ensures only one instance across all servers executes a method at a time.","archived":false,"fork":false,"pushed_at":"2026-01-25T23:00:08.000Z","size":222,"stargazers_count":7,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-26T12:59:02.870Z","etag":null,"topics":["aspectj","java","spring-boot"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/riido-git.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-20T12:41:00.000Z","updated_at":"2026-01-25T21:34:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/riido-git/locksmith","commit_stats":null,"previous_names":["riido-git/locksmith"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/riido-git/locksmith","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/riido-git%2Flocksmith","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/riido-git%2Flocksmith/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/riido-git%2Flocksmith/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/riido-git%2Flocksmith/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/riido-git","download_url":"https://codeload.github.com/riido-git/locksmith/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/riido-git%2Flocksmith/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29175844,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-06T20:14:21.878Z","status":"ssl_error","status_checked_at":"2026-02-06T20:14:21.443Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aspectj","java","spring-boot"],"created_at":"2025-12-27T14:39:51.066Z","updated_at":"2026-02-06T21:04:27.351Z","avatar_url":"https://github.com/riido-git.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Locksmith\n\n[![Maven Central](https://img.shields.io/maven-central/v/in.riido/locksmith-spring-boot-starter)](https://central.sonatype.com/artifact/in.riido/locksmith-spring-boot-starter)\n\nA Spring Boot starter for Redis-based distributed locking, semaphores, and rate limiting using annotations.\n\n## Overview\n\nLocksmith provides three coordination primitives for distributed systems:\n\n| Primitive | Purpose | Example Use Case |\n|-----------|---------|------------------|\n| `@DistributedLock` | Exclusive access - only one instance executes at a time | Payment processing, scheduled jobs |\n| `@DistributedSemaphore` | Limited concurrency - up to N instances execute simultaneously | Connection pooling, batch processing |\n| `@RateLimit` | Throughput control - limit requests per time interval | API rate limiting, throttling |\n\n## Requirements\n\n- Java 17+\n- Spring Boot 4.0+\n- Redis\n- Redisson 4.0+\n\n## Installation\n\nAdd to your `pom.xml`:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ein.riido\u003c/groupId\u003e\n    \u003cartifactId\u003elocksmith-spring-boot-starter\u003c/artifactId\u003e\n    \u003cversion\u003e3.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.redisson\u003c/groupId\u003e\n    \u003cartifactId\u003eredisson\u003c/artifactId\u003e\n    \u003cversion\u003e4.2.0\u003c/version\u003e\n\u003c/dependency\u003e\n\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.aspectj\u003c/groupId\u003e\n    \u003cartifactId\u003easpectjweaver\u003c/artifactId\u003e\n\u003c/dependency\u003e\n```\n\nFor Gradle:\n\n```groovy\nimplementation 'in.riido:locksmith-spring-boot-starter:3.0.0'\nimplementation 'org.redisson:redisson:4.2.0'\nimplementation 'org.aspectj:aspectjweaver'\n```\n\n## Quick Start\n\n### 1. Configure Redis Connection\n\nProvide a `RedissonClient` bean:\n\n```java\n@Configuration\npublic class RedisConfig {\n\n    @Bean\n    public RedissonClient redissonClient() {\n        Config config = new Config();\n        config.useSingleServer()\n              .setAddress(\"redis://localhost:6379\");\n        return Redisson.create(config);\n    }\n}\n```\n\n### 2. Use Annotations\n\n```java\n@Service\npublic class OrderService {\n\n    // Only one instance processes this order at a time\n    @DistributedLock(key = \"#{'order-' + #orderId}\")\n    public void processOrder(String orderId) {\n        // Critical section\n    }\n\n    // Up to 5 concurrent API calls across all instances\n    @DistributedSemaphore(key = \"external-api\", permits = 5)\n    public Response callExternalApi() {\n        return httpClient.get(\"/api/data\");\n    }\n\n    // Maximum 100 requests per minute\n    @RateLimit(key = \"api-endpoint\", permits = 100, interval = \"1m\")\n    public Response handleRequest() {\n        return processRequest();\n    }\n}\n```\n\n## Distributed Locks\n\nUse `@DistributedLock` when only one instance should execute a method at a time.\n\n```java\n// Basic lock\n@DistributedLock(key = \"my-task\")\npublic void exclusiveTask() { }\n\n// Dynamic key using SpEL (must use #{...} wrapper)\n@DistributedLock(key = \"#{#userId}\")\npublic void processUser(String userId) { }\n\n// Wait up to 30 seconds for lock\n@DistributedLock(key = \"resource\", mode = AcquisitionMode.WAIT_AND_SKIP, waitTime = \"30s\")\npublic void waitForLock() { }\n\n// Auto-renew for long-running tasks\n@DistributedLock(key = \"long-task\", autoRenew = true)\npublic void longRunningTask() { }\n\n// Read/Write locks for concurrent reads\n@DistributedLock(key = \"data\", type = LockType.READ)\npublic Data readData() { }\n\n@DistributedLock(key = \"data\", type = LockType.WRITE)\npublic void writeData(Data data) { }\n```\n\n**Handling Lock Failures:**\n\n```java\n// Default: throws LockNotAcquiredException\n@DistributedLock(key = \"task\")\npublic void task() { }\n\n// Silent skip: returns null/default value\n@DistributedLock(key = \"task\", skipHandler = LockReturnDefaultHandler.class)\npublic void task() { }\n```\n\n## Distributed Semaphores\n\nUse `@DistributedSemaphore` to limit concurrent executions to N instances.\n\n```java\n// Allow 10 concurrent executions\n@DistributedSemaphore(key = \"db-pool\", permits = 10)\npublic void queryDatabase() { }\n\n// Per-user concurrency limit\n@DistributedSemaphore(key = \"#{#userId}\", permits = 3)\npublic void userOperation(String userId) { }\n\n// Wait for permit\n@DistributedSemaphore(key = \"pool\", permits = 5, mode = AcquisitionMode.WAIT_AND_SKIP, waitTime = \"30s\")\npublic void waitForPermit() { }\n```\n\n## Rate Limiting\n\nUse `@RateLimit` to control request throughput over time.\n\n```java\n// 10 requests per second (default)\n@RateLimit(key = \"api\")\npublic void apiCall() { }\n\n// 100 requests per minute\n@RateLimit(key = \"heavy-api\", permits = 100, interval = \"1m\")\npublic void heavyOperation() { }\n\n// Per-user rate limiting\n@RateLimit(key = \"#{#userId}\", permits = 60, interval = \"1m\")\npublic void userRequest(String userId) { }\n\n// Per-instance rate limiting\n@RateLimit(key = \"local-api\", permits = 50, interval = \"1s\", type = RateType.PER_CLIENT)\npublic void localOperation() { }\n```\n\n## Programmatic API\n\nFor scenarios where annotations are not suitable:\n\n```java\n@Service\npublic class MyService {\n\n    private final LocksmithLockTemplate lockTemplate;\n    private final LocksmithSemaphoreTemplate semaphoreTemplate;\n    private final LocksmithRateLimitTemplate rateLimitTemplate;\n\n    // Lock with callback\n    public String withLock() {\n        return lockTemplate.executeWithLock(\"my-key\", () -\u003e {\n            return computeResult();\n        });\n    }\n\n    // Lock with builder\n    public void customLock() {\n        lockTemplate.forKey(\"my-key\")\n            .waitTime(Duration.ofSeconds(30))\n            .leaseTime(Duration.ofMinutes(5))\n            .lockType(LockType.WRITE)\n            .execute(() -\u003e doWork());\n    }\n\n    // Semaphore with callback\n    public String withSemaphore() {\n        return semaphoreTemplate.executeWithPermit(\"pool\", 5, () -\u003e {\n            return callApi();\n        });\n    }\n\n    // Rate limit with callback\n    public String withRateLimit() {\n        return rateLimitTemplate.executeWithRateLimit(\"api\", () -\u003e {\n            return processRequest();\n        });\n    }\n}\n```\n\n## Configuration\n\n```yaml\nlocksmith:\n  lock:\n    enabled: true           # Enable/disable locks\n    lease-time: 10m         # Auto-release time\n    wait-time: 60s          # Wait time for WAIT_AND_SKIP\n    key-prefix: \"lock:\"     # Redis key prefix\n    metrics-enabled: false  # Micrometer metrics\n  semaphore:\n    enabled: true\n    lease-time: 5m\n    wait-time: 60s\n    key-prefix: \"semaphore:\"\n    metrics-enabled: false\n  rate-limit:\n    enabled: true\n    wait-time: 60s\n    key-prefix: \"ratelimit:\"\n    metrics-enabled: false\n```\n\n## SpEL Key Syntax\n\nDynamic keys use Spring Expression Language. **SpEL expressions must be wrapped in `#{...}`:**\n\n| Expression | Type | Result |\n|------------|------|--------|\n| `\"my-task\"` | Literal | `my-task` |\n| `\"order#123\"` | Literal | `order#123` |\n| `\"#{#userId}\"` | SpEL | Value of `userId` parameter |\n| `\"#{'user-' + #id}\"` | SpEL | `user-42` (concatenation) |\n| `\"#{#order.customerId}\"` | SpEL | Property access |\n\n## Exception Handling\n\n```java\ntry {\n    lockedMethod();\n} catch (LockNotAcquiredException e) {\n    // Lock was not acquired\n} catch (LeaseExpiredException e) {\n    // Method exceeded lease time\n}\n\ntry {\n    semaphoreMethod();\n} catch (SemaphoreNotAcquiredException e) {\n    // No permit available\n}\n\ntry {\n    rateLimitedMethod();\n} catch (RateLimitExceededException e) {\n    // Rate limit exceeded\n}\n```\n\n## Documentation\n\nFor detailed documentation, see the **[Wiki](https://github.com/riido-git/locksmith/wiki)**:\n\n- [Installation](https://github.com/riido-git/locksmith/wiki/Installation)\n- [Configuration](https://github.com/riido-git/locksmith/wiki/Configuration)\n- [Distributed Locks](https://github.com/riido-git/locksmith/wiki/Distributed-Locks)\n- [Distributed Semaphores](https://github.com/riido-git/locksmith/wiki/Distributed-Semaphores)\n- [Rate Limiting](https://github.com/riido-git/locksmith/wiki/Rate-Limiting)\n- [Dynamic Keys with SpEL](https://github.com/riido-git/locksmith/wiki/Dynamic-Keys-with-SpEL)\n- [Lock Types (Read/Write)](https://github.com/riido-git/locksmith/wiki/Lock-Types)\n- [Auto-Renew Lease Time](https://github.com/riido-git/locksmith/wiki/Auto-Renew-Lease-Time)\n- [Skip Handlers](https://github.com/riido-git/locksmith/wiki/Skip-Handlers)\n- [Programmatic Templates](https://github.com/riido-git/locksmith/wiki/Programmatic-Templates)\n- [Micrometer Metrics](https://github.com/riido-git/locksmith/wiki/Micrometer-Metrics)\n- [High Concurrency Best Practices](https://github.com/riido-git/locksmith/wiki/High-Concurrency-Best-Practices)\n- [Troubleshooting](https://github.com/riido-git/locksmith/wiki/Troubleshooting)\n\n## Issues\n\nFound a bug or have a feature request? [Create an issue](https://github.com/riido-git/locksmith/issues).\n\n## License\n\nApache License 2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Friido-git%2Flocksmith","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Friido-git%2Flocksmith","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Friido-git%2Flocksmith/lists"}