Skip to content

Commit dd4569f

Browse files
authored
Implements retry mechanism with backoff for SVN checkout of Derby (#158)
Adds retry mechanism when checkout Derby from SVN repository. Create a decorator method that can handle the retries of an SVN action. By default retries 5 times with an incremental backoff from 1 to 16 seconds.
1 parent f860943 commit dd4569f

File tree

2 files changed

+55
-4
lines changed

2 files changed

+55
-4
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
## Unreleased
2+
- Adds retry mechanism when checkout Derby from SVN repository [#158](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/158)
3+
14
## 5.4.9
25
- Fix Derby missed driver classes when built locally for version 10.15 [#160](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/160)
3-
-
6+
47
## 5.4.8
58
- Update Derby with locally built 10.15.2.1 version [#155](https://github.com/logstash-plugins/logstash-integration-jdbc/pull/155)
69

build.gradle

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import java.nio.file.Files
22
import org.tmatesoft.svn.core.SVNDepth
33
import org.tmatesoft.svn.core.SVNURL
4+
import org.tmatesoft.svn.core.SVNException
5+
import org.tmatesoft.svn.core.SVNErrorCode
46
import org.tmatesoft.svn.core.wc.SVNClientManager
57
import org.tmatesoft.svn.core.wc.SVNRevision
68
import org.tmatesoft.svn.core.wc.SVNUpdateClient
@@ -68,9 +70,55 @@ class SvnCheckout extends DefaultTask {
6870
SVNURL svnurl = SVNURL.parseURIEncoded(svnRef + branch);
6971

7072
println "Starting checkout"
71-
long revision = client.doCheckout(svnurl, checkoutDir, SVNRevision.HEAD,
72-
SVNRevision.create(revision), SVNDepth.UNKNOWN, true);
73-
println "Checked out at revision ${revision} in folder ${checkoutDir}"
73+
retryWithBackoff() {
74+
long revision = client.doCheckout(svnurl, checkoutDir, SVNRevision.HEAD,
75+
SVNRevision.create(revision), SVNDepth.UNKNOWN, true);
76+
println "Checked out at revision ${revision} in folder ${checkoutDir}"
77+
}
78+
}
79+
80+
/**
81+
* @param numRetries number of total reties before giving up with the action invocation. A value of 0 means no retries.
82+
* @param initialPause initial time to delay between calls, in milliseconds.
83+
* @param action the action to execute with retry mechanism in case of SVN error.
84+
* */
85+
protected def retryWithBackoff(int numRetries = 5, int initialPause = 1_000, Closure action) {
86+
int incrementalBackoff = initialPause
87+
do {
88+
try {
89+
// executes the action to protect with retries
90+
action()
91+
92+
numRetries = 0
93+
} catch (Exception ex) {
94+
if (!isSvnCheckoutError(ex)) {
95+
// if error not recognized as recoverable, bubble up
96+
throw ex
97+
}
98+
99+
// IO error, retry
100+
println "Received SVN error ${ex}, retry number ${numRetries} sleeping ${incrementalBackoff} millis"
101+
sleep(incrementalBackoff)
102+
incrementalBackoff = incrementalBackoff * 2 // 1, 2, 4, 8, 16 seconds
103+
numRetries--
104+
if (numRetries <= 0) {
105+
throw new IllegalStateException("Consumed all retries, failing the task", ex)
106+
}
107+
}
108+
} while (numRetries > 0)
109+
}
110+
111+
private boolean isSvnCheckoutError(Exception ex) {
112+
if (ex instanceof SVNException) {
113+
SVNException svnex = (SVNException) ex
114+
SVNErrorCode svnErrorCode = svnex.getErrorMessage().getErrorCode()
115+
116+
// SVN error code 175002 is "Premature end of file."
117+
if (svnErrorCode == SVNErrorCode.IO_ERROR || svnErrorCode.getCode() == 175002) {
118+
return true
119+
}
120+
}
121+
return false
74122
}
75123
}
76124

0 commit comments

Comments
 (0)