Use Promise Disposer for lock, + cleanup

This commit is contained in:
Pablo Carranza Vélez 2015-08-10 17:46:30 +00:00
parent 685af77007
commit c2496d30c2
4 changed files with 37 additions and 42 deletions

View File

@ -22,7 +22,7 @@ func TestPurge(t *testing.T) {
if err = os.MkdirAll(dataPath, 0755); err != nil {
t.Fatal("Could not create test directory for purge")
} else if err = ioutil.WriteFile(dataPath+"/test", []byte("test"), 777); err != nil {
} else if err = ioutil.WriteFile(dataPath+"/test", []byte("test"), 0777); err != nil {
t.Fatal("Could not create test file for purge")
}

View File

@ -42,31 +42,29 @@ func TestPurge(t *testing.T) {
appId := config.ApplicationId
dataPath := "/resin-data/" + appId
if err := ioutil.WriteFile(dataPath+"/test", []byte("test"), 777); err != nil {
if err := ioutil.WriteFile(dataPath+"/test", []byte("test"), 0777); err != nil {
t.Fatal("Could not create test file for purge")
} else if request, err := http.NewRequest("POST", supervisorAddress+"/v1/purge?apikey=bananas", strings.NewReader(`{"appId": "`+appId+`"}`)); err != nil {
t.Fatal(err)
} else {
request.Header.Set("Content-Type", "application/json")
if response, err := http.DefaultClient.Do(request); err != nil {
response, err := http.DefaultClient.Do(request)
defer response.Body.Close()
if err != nil {
t.Fatal(err)
} else if response.StatusCode != http.StatusOK {
t.Errorf("Expected 200, got %d", response.StatusCode)
defer response.Body.Close()
if contents, err := ioutil.ReadAll(response.Body); err != nil {
t.Fatal(err)
} else {
t.Fatalf("Response: %s", contents)
}
} else {
defer response.Body.Close()
if contents, err := ioutil.ReadAll(response.Body); err != nil {
t.Fatal(err)
} else if !strings.EqualFold(string(contents), `{"Status":"OK","Error":""}`) {
t.Errorf("Purge response didn't match the expected JSON, got: %s", contents)
}
if dirContents, err := ioutil.ReadDir(dataPath); err != nil {
t.Errorf("Could not read the data path after purge: %s", err)
} else if len(dirContents) > 0 {

View File

@ -67,21 +67,20 @@ module.exports = (secret) ->
utils.mixpanelTrack('Purge /data', appId)
if !appId?
return res.status(400).send('Missing app id')
app = null
knex('app').select().where({ appId })
.then ([ appFromDB ]) ->
if !appFromDB?
.then ([ app ]) ->
if !app?
throw new Error('App not found')
app = appFromDB
application.lockUpdatesAsync()
.tap ->
application.kill(app)
.then (release) ->
request.post config.gosuperAddress + '/v1/purge', { json: true, body: applicationId: appId }, ->
application.start(app)
Promise.using application.lockUpdates(), ->
application.kill(app)
.then ->
release()
.pipe(res)
new Promise (resolve, reject) ->
request.post(config.gosuperAddress + '/v1/purge', { json: true, body: applicationId: appId })
.on 'error', reject
.on 'response', -> resolve()
.pipe(res)
.finally ->
application.start(app)
.catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error')

View File

@ -242,9 +242,10 @@ getEnvironment = do ->
console.error("Failed to get environment for device #{deviceId}, app #{appId}. #{err}")
throw err
lock = new Lock()
exports.lockUpdates = lockUpdates = lock.async.writeLock
exports.lockUpdatesAsync = lockUpdatesAsync = Promise.promisify(lockUpdates)
exports.lockUpdates = lockUpdates = do ->
_lock = new Lock()
_lockUpdates = Promise.promisify(_lock.async.writeLock)
return -> _lockUpdates().disposer (release) -> release()
# 0 - Idle
# 1 - Updating
@ -325,27 +326,24 @@ exports.update = update = ->
app = remoteApps[imageId]
fetch(app)
.then ->
lockUpdatesAsync()
.tap ->
# Then delete all the ones to remove in one go
Promise.map toBeRemoved, (imageId) ->
kill(apps[imageId])
.tap ->
# Then install the apps and add each to the db as they succeed
installingPromises = toBeInstalled.map (imageId) ->
app = remoteApps[imageId]
start(app)
# And remove/recreate updated apps and update db as they succeed
updatingPromises = toBeUpdated.map (imageId) ->
localApp = apps[imageId]
app = remoteApps[imageId]
logSystemEvent(logTypes.updateApp, app)
kill(localApp)
Promise.using lockUpdates(), ->
# Then delete all the ones to remove in one go
Promise.map toBeRemoved, (imageId) ->
kill(apps[imageId])
.then ->
start(app)
Promise.all(installingPromises.concat(updatingPromises))
.then (release) ->
release()
# Then install the apps and add each to the db as they succeed
installingPromises = toBeInstalled.map (imageId) ->
app = remoteApps[imageId]
start(app)
# And remove/recreate updated apps and update db as they succeed
updatingPromises = toBeUpdated.map (imageId) ->
localApp = apps[imageId]
app = remoteApps[imageId]
logSystemEvent(logTypes.updateApp, app)
kill(localApp)
.then ->
start(app)
Promise.all(installingPromises.concat(updatingPromises))
.then ->
failedUpdates = 0
# We cleanup here as we want a point when we have a consistent apps/images state, rather than potentially at a