Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request - Manual Lock Release #2336

Open
caladotiago opened this issue Jan 8, 2025 · 1 comment
Open

Feature Request - Manual Lock Release #2336

caladotiago opened this issue Jan 8, 2025 · 1 comment

Comments

@caladotiago
Copy link

Is your feature request related to a problem? Please describe.

I plan to implement Shedlock as my unique locking solution, handling both scheduled tasks and concurrent web requests within my system.

While the implementation is moving forward, I've identified a specific scenario where the current approach falls short of the required functionality.

Suppose a configuration that locks the given key for one second

  1. The first request will pass and activate the lock for one second.
  2. The following requests passing by the same lock key while the first one is being executed will be blocked
  3. After the conclusion of the first request, the lock will not be released, so the subsequent ones have to wait until the expiration time to allow another request

I want to be capable to manually release the lock when the first request is done and allow future requests before the expiration time.

Situation
image

Intention
image

Describe the solution you'd like

I'd like to have an unlock option, as an annotation, or method, to be capable to release the given lock manually.

Describe alternatives you've considered

  • I have considered to lower my lock time, but I cannot predict the request latency.
  • I have considered to use another lock solution, but I already use shedock as scheduler lock and want to use an all-in-one solution

Additional context

Here is an example implementation of request locking in the project that i am working on:
I am utilizing Java with Spring and my LockProvider is set up to work with JDBC.

Controller:

@RestController  
@AllArgsConstructor  
@RequestMapping("/v1/customers/{customerId}/")  
public class MyRestService {  
  
    private final MyService service; 
  
    @ResponseStatus(ACCEPTED)  
    @PostMapping("/{id}")
    public ResponseDTO doSomething(@PathVariable String customerId, @PathVariable String id) {  
       return service.doSomething(customerId, id);  
    }  
  
}

Business Logic Method:

@Service  
@AllArgsConstructor  
@Transactional(rollbackFor = Exception.class)  
public class MyService {  
    private final LockService lockService;  
  
    public ResponseDTO doSomething(String customerId, String id) {  
       TaskWithResult<ResponseDTO> task = () -> start(customerId, id);  
       String lockName = "my-lock-" + customerId + " - " + id;  
       return lockService.executeWithLock(lockName, 1, task);  
    } 

    private ResponseDTO start(String customerId, String id) {  
        // do something...
    }
}

Lock service:

@Component  
@AllArgsConstructor  
public class LockService {  
    private final LockProvider lockProvider;  
  
    public <T> T executeWithLock(String lockName, long durationInSeconds, TaskWithResult<T> task) {  
       LockingTaskExecutor executor = new DefaultLockingTaskExecutor(lockProvider);  
  
       Duration duration = Duration.ofSeconds(durationInSeconds);  
       LockConfiguration lockConfiguration = new LockConfiguration(Instant.now(), lockName, duration, duration);  
  
       TaskResult<T> result = execute(task, executor, lockConfiguration);  
  
       if (!result.wasExecuted()) {  
          throw new BusinessLogicException("unexpected-error");  
       }  
  
       return result.getResult();  
    }  
  
    private static <T> TaskResult<T> execute(TaskWithResult<T> task, LockingTaskExecutor executor,  
          LockConfiguration lockConfiguration) {  
       try {  
          return executor.executeWithLock(task, lockConfiguration);  
       }  
       catch (Throwable e) {  
          throw new RuntimeException(e);  
       }  
    }  
}

Final Considerations

If you consider the request valid I am willing to help with the feature implementation.

@lukas-krecan
Copy link
Owner

lukas-krecan commented Jan 13, 2025

Hi, sorry, but I don't understand what you are asking for. Currently, in ShedLock

  1. If one task holds the lock, other tasks are not blocked but skipped.
  2. If a tasks finished, the lock is released at once, unless you specify lockAtLeastFor

Regardless of what you are asking for, I am generally reluctant to change behavior for unusual requirements, as I try to keep the complixity of the library as low as possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants