Skip to content

Commit f600361

Browse files
artembilangaryrussell
authored andcommitted
GH-3010 Add idleBetweenTries for JdbcLockRegistry
Fixes #3010 Sometimes `100` milliseconds interval is too often to try to obtain a lock with `UPDATE/INSERT` queries **Cherry-pick to 5.1.x**
1 parent f0807fe commit f600361

File tree

2 files changed

+30
-10
lines changed

2 files changed

+30
-10
lines changed

spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/lock/JdbcLockRegistry.java

+27-10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.integration.jdbc.lock;
1818

19+
import java.time.Duration;
1920
import java.util.Iterator;
2021
import java.util.Map;
2122
import java.util.Map.Entry;
@@ -55,15 +56,28 @@ public class JdbcLockRegistry implements ExpirableLockRegistry {
5556

5657
private final LockRepository client;
5758

59+
private Duration idleBetweenTries = Duration.ofMillis(100);
60+
5861
public JdbcLockRegistry(LockRepository client) {
5962
this.client = client;
6063
}
6164

65+
/**
66+
* Specify a @link Duration} to sleep between lock record insert/update attempts.
67+
* Defaults to 100 milliseconds.
68+
* @param idleBetweenTries the {@link Duration} to sleep between insert/update attempts.
69+
* @since 5.1.8
70+
*/
71+
public void setIdleBetweenTries(Duration idleBetweenTries) {
72+
Assert.notNull(idleBetweenTries, "'idleBetweenTries' must not be null");
73+
this.idleBetweenTries = idleBetweenTries;
74+
}
75+
6276
@Override
6377
public Lock obtain(Object lockKey) {
6478
Assert.isInstanceOf(String.class, lockKey);
6579
String path = pathFor((String) lockKey);
66-
return this.locks.computeIfAbsent(path, p -> new JdbcLock(this.client, p));
80+
return this.locks.computeIfAbsent(path, (key) -> new JdbcLock(this.client, this.idleBetweenTries, key));
6781
}
6882

6983
private String pathFor(String input) {
@@ -87,14 +101,17 @@ private static final class JdbcLock implements Lock {
87101

88102
private final LockRepository mutex;
89103

104+
private final Duration idleBetweenTries;
105+
90106
private final String path;
91107

92108
private volatile long lastUsed = System.currentTimeMillis();
93109

94110
private final ReentrantLock delegate = new ReentrantLock();
95111

96-
JdbcLock(LockRepository client, String path) {
112+
JdbcLock(LockRepository client, Duration idleBetweenTries, String path) {
97113
this.mutex = client;
114+
this.idleBetweenTries = idleBetweenTries;
98115
this.path = path;
99116
}
100117

@@ -108,19 +125,19 @@ public void lock() {
108125
while (true) {
109126
try {
110127
while (!doLock()) {
111-
Thread.sleep(100); //NOSONAR
128+
Thread.sleep(this.idleBetweenTries.toMillis());
112129
}
113130
break;
114131
}
115132
catch (TransientDataAccessException e) {
116133
// try again
117134
}
118135
catch (InterruptedException e) {
119-
/*
120-
* This method must be uninterruptible so catch and ignore
121-
* interrupts and only break out of the while loop when
122-
* we get the lock.
123-
*/
136+
/*
137+
* This method must be uninterruptible so catch and ignore
138+
* interrupts and only break out of the while loop when
139+
* we get the lock.
140+
*/
124141
}
125142
catch (Exception e) {
126143
this.delegate.unlock();
@@ -139,7 +156,7 @@ public void lockInterruptibly() throws InterruptedException {
139156
while (true) {
140157
try {
141158
while (!doLock()) {
142-
Thread.sleep(100); //NOSONAR
159+
Thread.sleep(this.idleBetweenTries.toMillis());
143160
if (Thread.currentThread().isInterrupted()) {
144161
throw new InterruptedException();
145162
}
@@ -183,7 +200,7 @@ public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
183200
while (true) {
184201
try {
185202
while (!(acquired = doLock()) && System.currentTimeMillis() < expire) { //NOSONAR
186-
Thread.sleep(100); //NOSONAR
203+
Thread.sleep(this.idleBetweenTries.toMillis());
187204
}
188205
if (!acquired) {
189206
this.delegate.unlock();

src/reference/asciidoc/jdbc.adoc

+3
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,9 @@ The `timeToLive` (TTL) option on the `DefaultLockRepository` is provided for thi
10861086
You may also want to specify `CLIENT_ID` for the locks stored for a given `DefaultLockRepository` instance.
10871087
If so, you can specify the `id` to be associated with the `DefaultLockRepository` as a constructor parameter.
10881088

1089+
Starting with version 5.1.8, the `JdbcLockRegistry` can be configured with the `idleBetweenTries` - a `Duration` to sleep between lock record insert/update executions.
1090+
By default it is `100` milliseconds and in some environments non-leaders pollute connections with data source too often.
1091+
10891092
[[jdbc-metadata-store]]
10901093
=== JDBC Metadata Store
10911094

0 commit comments

Comments
 (0)