|
1 | 1 | import java.nio.file.Files |
2 | 2 | import org.tmatesoft.svn.core.SVNDepth |
3 | 3 | import org.tmatesoft.svn.core.SVNURL |
| 4 | +import org.tmatesoft.svn.core.SVNException |
| 5 | +import org.tmatesoft.svn.core.SVNErrorCode |
4 | 6 | import org.tmatesoft.svn.core.wc.SVNClientManager |
5 | 7 | import org.tmatesoft.svn.core.wc.SVNRevision |
6 | 8 | import org.tmatesoft.svn.core.wc.SVNUpdateClient |
@@ -68,9 +70,55 @@ class SvnCheckout extends DefaultTask { |
68 | 70 | SVNURL svnurl = SVNURL.parseURIEncoded(svnRef + branch); |
69 | 71 |
|
70 | 72 | 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 |
74 | 122 | } |
75 | 123 | } |
76 | 124 |
|
|
0 commit comments