Fix multiple update loops appearing after a long period of updates failing.

This commit is contained in:
Pagan Gazzard 2016-10-21 15:16:46 -07:00
parent 40298f24d6
commit 4ed64536ec
2 changed files with 28 additions and 14 deletions

View File

@ -1,3 +1,4 @@
* Fixed multiple update loops appearing after a long period of updates failing. [Page]
* Avoid restarting the app if the device name changes [Pablo] * Avoid restarting the app if the device name changes [Pablo]
* Use appId in dependent app assets tar path, and only create the tar if it doesn't exist [Pablo] * Use appId in dependent app assets tar path, and only create the tar if it doesn't exist [Pablo]
* Support AUFS by upgrading node-docker-delta to 1.0.0 and docker-toolbelt to 1.3.0 [Pablo] * Support AUFS by upgrading node-docker-delta to 1.0.0 and docker-toolbelt to 1.3.0 [Pablo]

View File

@ -445,6 +445,7 @@ waitToKill = (app, timeout) ->
UPDATE_IDLE = 0 UPDATE_IDLE = 0
UPDATE_UPDATING = 1 UPDATE_UPDATING = 1
UPDATE_REQUIRED = 2 UPDATE_REQUIRED = 2
UPDATE_SCHEDULED = 3
updateStatus = updateStatus =
state: UPDATE_IDLE state: UPDATE_IDLE
@ -582,9 +583,16 @@ compareForUpdate = (localApps, remoteApps) ->
allAppIds = _.union(localAppIds, remoteAppIds) allAppIds = _.union(localAppIds, remoteAppIds)
return { toBeRemoved, toBeDownloaded, toBeInstalled, toBeUpdated, appsWithUpdatedConfigs, allAppIds } return { toBeRemoved, toBeDownloaded, toBeInstalled, toBeUpdated, appsWithUpdatedConfigs, allAppIds }
application.update = update = (force) -> application.update = update = (force, scheduled = false) ->
if updateStatus.state isnt UPDATE_IDLE switch updateStatus.state
# Mark an update required after the current. when UPDATE_SCHEDULED
if scheduled isnt true
# There's an update scheduled but it isn't this one, so just stop
return
when UPDATE_IDLE
# All good, carry on with the update.
else
# Mark an update required after the current in-progress update.
updateStatus.forceNext = force updateStatus.forceNext = force
updateStatus.state = UPDATE_REQUIRED updateStatus.state = UPDATE_REQUIRED
return return
@ -680,21 +688,26 @@ application.update = update = (force) ->
.catch (err) -> .catch (err) ->
updateStatus.failed++ updateStatus.failed++
device.setUpdateState(update_failed: true) device.setUpdateState(update_failed: true)
if updateStatus.state is UPDATE_REQUIRED if updateStatus.state in [ UPDATE_REQUIRED, UPDATE_SCHEDULED ]
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((2 ** 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 || updateStatus.forceNext, true)
updateStatus.state = UPDATE_SCHEDULED
.finally -> .finally ->
device.updateState(status: 'Idle') switch updateStatus.state
if updateStatus.state is UPDATE_REQUIRED when UPDATE_REQUIRED
# If an update is required then schedule it # If an update is required then schedule it
setTimeout(update, 1, updateStatus.forceNext) setTimeout(update, 1, updateStatus.forceNext, true)
.finally -> updateStatus.state = UPDATE_SCHEDULED
# Set the updating as finished in its own block, so it never has to worry about other code stopping this. when UPDATE_SCHEDULED
# Already scheduled, nothing to do here
else
updateStatus.state = UPDATE_IDLE updateStatus.state = UPDATE_IDLE
device.updateState(status: 'Idle')
return
listenToEvents = do -> listenToEvents = do ->
appHasDied = {} appHasDied = {}