mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-05-07 03:18:12 +00:00
Catch out of sync errors falling back to scratch. Make update retries more dependent on number of failures
This commit is contained in:
parent
d3fea26c11
commit
9dd1fa2408
@ -586,7 +586,7 @@ application.update = update = (force) ->
|
|||||||
if updateStatus.state is UPDATE_REQUIRED
|
if updateStatus.state is UPDATE_REQUIRED
|
||||||
console.log('Updating failed, but there is already another update scheduled immediately: ', err)
|
console.log('Updating failed, but there is already another update scheduled immediately: ', err)
|
||||||
return
|
return
|
||||||
delayTime = Math.min(updateStatus.failed * 500, 30000)
|
delayTime = Math.min((2 ** updateStatus.failed) * 500, 30000)
|
||||||
# If there was an error then schedule another attempt briefly in the future.
|
# If there was an error then schedule another attempt briefly in the future.
|
||||||
console.log('Scheduling another update attempt due to failure: ', delayTime, err)
|
console.log('Scheduling another update attempt due to failure: ', delayTime, err)
|
||||||
setTimeout(update, delayTime, force)
|
setTimeout(update, delayTime, force)
|
||||||
|
@ -6,9 +6,11 @@ progress = require 'request-progress'
|
|||||||
config = require './config'
|
config = require './config'
|
||||||
_ = require 'lodash'
|
_ = require 'lodash'
|
||||||
knex = require './db'
|
knex = require './db'
|
||||||
|
TypedError = require 'typed-error'
|
||||||
{ request } = require './request'
|
{ request } = require './request'
|
||||||
|
|
||||||
|
class OutOfSyncError extends TypedError
|
||||||
|
|
||||||
docker = Promise.promisifyAll(new Docker(socketPath: config.dockerSocket))
|
docker = Promise.promisifyAll(new Docker(socketPath: config.dockerSocket))
|
||||||
# Hack dockerode to promisify internal classes' prototypes
|
# Hack dockerode to promisify internal classes' prototypes
|
||||||
Promise.promisifyAll(docker.getImage().constructor.prototype)
|
Promise.promisifyAll(docker.getImage().constructor.prototype)
|
||||||
@ -39,24 +41,32 @@ findSimilarImage = (repoTag) ->
|
|||||||
for repoTag in repoTags
|
for repoTag in repoTags
|
||||||
otherApplication = repoTag[0].split('/')[1]
|
otherApplication = repoTag[0].split('/')[1]
|
||||||
if otherApplication is application
|
if otherApplication is application
|
||||||
return repoTag
|
return repoTag[0]
|
||||||
|
|
||||||
# Otherwise return the image for the most specific supervisor tag (commit hash)
|
# Otherwise return the image for the most specific supervisor tag (commit hash)
|
||||||
for repoTag in repoTags when /resin\/.*-supervisor.*:[0-9a-f]{6}/.test(repoTag[0])
|
for repoTag in repoTags when /resin\/.*-supervisor.*:[0-9a-f]{6}/.test(repoTag[0])
|
||||||
return repoTag
|
return repoTag[0]
|
||||||
|
|
||||||
# Or return *any* supervisor image available (except latest which is usually a phony tag)
|
# Or return *any* supervisor image available (except latest which is usually a phony tag)
|
||||||
for repoTag in repoTags when /resin\/.*-supervisor.*:(?!latest)/.test(repoTag[0])
|
for repoTag in repoTags when /resin\/.*-supervisor.*:(?!latest)/.test(repoTag[0])
|
||||||
return repoTag
|
return repoTag[0]
|
||||||
|
|
||||||
# If all else fails, return the newest image available
|
# If all else fails, return the newest image available
|
||||||
return repoTags[0]
|
for repoTag in repoTags when repoTag[0] isnt '<none>:<none>'
|
||||||
|
return repoTag[0]
|
||||||
|
|
||||||
exports.rsyncImageWithProgress = (imgDest, onProgress) ->
|
return 'resin/scratch'
|
||||||
findSimilarImage(imgDest)
|
|
||||||
.spread (imgSrc, imgSrcId) ->
|
DELTA_OUT_OF_SYNC_CODES = [23, 24]
|
||||||
|
|
||||||
|
exports.rsyncImageWithProgress = (imgDest, onProgress, startFromEmpty = false) ->
|
||||||
|
Promise.try ->
|
||||||
|
if startFromEmpty
|
||||||
|
return 'resin/scratch'
|
||||||
|
findSimilarImage(imgDest)
|
||||||
|
.then (imgSrc) ->
|
||||||
rsyncDiff = new Promise (resolve, reject) ->
|
rsyncDiff = new Promise (resolve, reject) ->
|
||||||
progress request.get("#{config.deltaHost}/api/v1/delta?src=#{imgSrc}&srcId=#{imgSrcId}&dest=#{imgDest}", timeout: 5 * 60 * 1000)
|
progress request.get("#{config.deltaHost}/api/v1/delta?src=#{imgSrc}&dest=#{imgDest}", timeout: 5 * 60 * 1000)
|
||||||
.on 'progress', (progress) ->
|
.on 'progress', (progress) ->
|
||||||
onProgress(percentage: progress.percent)
|
onProgress(percentage: progress.percent)
|
||||||
.on 'end', ->
|
.on 'end', ->
|
||||||
@ -78,16 +88,23 @@ exports.rsyncImageWithProgress = (imgDest, onProgress) ->
|
|||||||
return [ rsyncDiff, imageConfig, imgSrc ]
|
return [ rsyncDiff, imageConfig, imgSrc ]
|
||||||
.spread (rsyncDiff, imageConfig, imgSrc) ->
|
.spread (rsyncDiff, imageConfig, imgSrc) ->
|
||||||
new Promise (resolve, reject) ->
|
new Promise (resolve, reject) ->
|
||||||
dockersync = spawn('/app/src/dockersync.sh', [ imgSrc, imgDest, JSON.stringify(imageConfig) ], stdio: [ 'pipe', 'ignore', 'ignore' ])
|
dockersync = spawn('/app/src/dockersync.sh', [ imgSrc, imgDest, JSON.stringify(imageConfig) ], stdio: [ 'pipe', 'pipe', 'pipe' ])
|
||||||
.on 'error', reject
|
.on 'error', reject
|
||||||
.on 'exit', (code, signal) ->
|
.on 'exit', (code, signal) ->
|
||||||
if code isnt 0
|
if code in DELTA_OUT_OF_SYNC_CODES
|
||||||
|
reject(new OutOfSyncError("Incompatible image"))
|
||||||
|
else if code isnt 0
|
||||||
reject(new Error("rsync exited. code: #{code} signal: #{signal}"))
|
reject(new Error("rsync exited. code: #{code} signal: #{signal}"))
|
||||||
else
|
else
|
||||||
resolve()
|
resolve()
|
||||||
|
|
||||||
rsyncDiff.pipe(dockersync.stdin)
|
rsyncDiff.pipe(dockersync.stdin)
|
||||||
|
dockersync.stdout.pipe(process.stdout)
|
||||||
|
dockersync.stderr.pipe(process.stdout)
|
||||||
rsyncDiff.resume()
|
rsyncDiff.resume()
|
||||||
|
.catch OutOfSyncError, (err) ->
|
||||||
|
console.log('Falling back to delta-from-empty')
|
||||||
|
exports.rsyncImageWithProgress(imgDest, onProgress, true)
|
||||||
|
|
||||||
do ->
|
do ->
|
||||||
# Keep track of the images being fetched, so we don't clean them up whilst fetching.
|
# Keep track of the images being fetched, so we don't clean them up whilst fetching.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user