add a `LockTemplate` to simplify working with distributed Locks in Spring Integration
Please add a LockTemplate or something to make using the LockRegistry easier. It took a lot of attempts before I figured out the right combination of objects was. I've encapsulated it into a LockTemplate, as shown below, but I'm sure might see use cases I haven't yet addressed here.
import org.springframework.integration.support.locks.LockRegistry;
import org.springframework.util.ReflectionUtils;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
public class LockTemplate {
private final LockRegistry registry;
public LockTemplate(LockRegistry registry) {
this.registry = registry;
}
public <T> T executeWithLock(String key, int timeoutDuration, TimeUnit tu, Callable<T> callable) {
return this.doExecuteWithLock(key, lock -> lock.tryLock(timeoutDuration, tu), callable);
}
public <T> T executeWithLock(String key, Callable<T> callable) {
return this.doExecuteWithLock(key, Lock::tryLock, callable);
}
private <T> T doExecuteWithLock(
String key, ExceptionSwallowingFunction<Lock, Boolean> lockProducer, Callable<T> callable) {
try {
Lock lock = registry.obtain(key);
boolean lockAcquired = lockProducer.apply(lock);
if (lockAcquired) {
try {
return callable.call();
}
finally {
lock.unlock();
}
}
}
catch (Exception e) {
ReflectionUtils.rethrowRuntimeException(e);
}
return null;
}
private interface ExceptionSwallowingFunction<I, O> {
O apply(I i) throws Exception;
}
}
Hey, @joshlong !
I've seen your Spring Tip on the matter: https://spring.io/blog/2019/06/19/spring-tips-distributed-locks-with-spring-integration. It is awesome as usual. Thanks for that and sorry that it hasn't been so visible for you in the past.
I think we rally may accept your suggestion. Meanwhile consider to use existing WhileLockedProcessor:
/**
* A simple strategy callback class that allows you to provide
* a code that needs to be executed under {@link Lock} provided by
* {@link LockRegistry}
* A typical usage would be to provide implementation of {@link #whileLocked()} method and
* then call {@link #doWhileLocked()}
*
* @author Oleg Zhurakousky
* @since 2.2
*
*/
public abstract class WhileLockedProcessor {
It use used in the Framework like this, for example:
WhileLockedProcessor whileLockedProcessor = new WhileLockedProcessor(this.lockRegistry,
fileToWriteTo.getAbsolutePath()) {
@Override
protected void whileLocked() throws IOException {
if (append && FileWritingMessageHandler.this.newFileCallback != null && !fileToWriteTo.exists()) {
FileWritingMessageHandler.this.newFileCallback.accept(fileToWriteTo, requestMessage);
}
writeStringToFile(fileToWriteTo, append, content);
}
};
whileLockedProcessor.doWhileLocked();
Hope that helps a little.
However it isn't clear why it brings you some pain since the API is fully based on Java Lock and the pattern to use is exactly the same.
Thank you for the report anyway!