Skip to content

Commit

Permalink
add expected response in service async actions
Browse files Browse the repository at this point in the history
  • Loading branch information
satkunas committed Nov 13, 2024
1 parent be1dd63 commit ac76ca0
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 48 deletions.
33 changes: 6 additions & 27 deletions html/pfappserver/root/src/store/modules/cluster.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,45 +65,24 @@ const api = (state, server = store.state.system.hostname) => {
return apiCall.postQuiet(['service', id, 'restart'], { async: true }, { headers })
.then(response => {
const { data: { task_id } = {} } = response
return store.dispatch('pfqueue/pollTaskStatus', { task_id, headers }).then(response => {
const { restart } = response
if (parseInt(restart) > 0) {
return response
}
else {
throw new Error(i18n.t(`Could not restart {id} on {server}.`, { server, id }))
}
})
const expect = ({ item: { restart = 0 } = {} }) => (+restart > 0)
return store.dispatch('pfqueue/pollTaskStatus', { task_id, headers, expect })
})
},
start: id => {
return apiCall.postQuiet(['service', id, 'start'], { async: true }, { headers })
.then(response => {
const { data: { task_id } = {} } = response
return store.dispatch('pfqueue/pollTaskStatus', { task_id, headers }).then(response => {
const { start } = response
if (parseInt(start) > 0) {
return response
}
else {
throw new Error(i18n.t(`Could not start {id} on {server}.`, { server, id }))
}
})
const expect = ({ item: { start = 0 } = {} }) => (+start > 0)
return store.dispatch('pfqueue/pollTaskStatus', { task_id, headers, expect })
})
},
stop: id => {
return apiCall.postQuiet(['service', id, 'stop'], { async: true }, { headers })
.then(response => {
const { data: { task_id } = {} } = response
return store.dispatch('pfqueue/pollTaskStatus', { task_id, headers }).then(response => {
const { stop } = response
if (parseInt(stop) > 0) {
return response
}
else {
throw new Error(i18n.t(`Could not stop {id} on {server}.`, { server, id }))
}
})
const expect = ({ item: { stop = 0 } = {} }) => (+stop > 0)
return store.dispatch('pfqueue/pollTaskStatus', { task_id, headers, expect })
})
},
systemService: id => {
Expand Down
52 changes: 31 additions & 21 deletions html/pfappserver/root/src/store/modules/pfqueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,35 @@ const POLL_RETRY_NUM = 20
// delay between retries (seconds)
const POLL_RETRY_INTERVAL = 3

// grace period after initial command (seconds), avoid race-condition during pfperl-api restart
const POLL_GRACE_PERIOD = 10
const retry = ({ task_id, headers, expect }) => {
return new Promise((resolve, reject) => {
setTimeout(() => { // debounce retries
pollTaskStatus({ task_id, headers, expect })
.then(resolve)
.catch(err => {
if (err.message) { // AxiosError
const data = i18n.t('{message}. No response after {timeout} seconds, gave up after {retries} retries.', { message: err.message, timeout: POLL_RETRY_NUM * POLL_RETRY_INTERVAL, retries: POLL_RETRY_NUM })
reject({ response: { data } })
}
else { // recursion
reject(err)
}
})
}, POLL_RETRY_INTERVAL * 1E3)
})
}

const pollTaskStatus = ({ task_id, headers, grace_period = 0 }) => {
const pollTaskStatus = ({ task_id, headers, expect }) => {
return apiCall.getQuiet(`pfqueue/task/${task_id}/status/poll`, { headers }).then(response => {
if (expect && !expect(response.data)) { // handle unexpected response
if (!(task_id in retries))
retries[task_id] = 0
else
retries[task_id]++
if (retries[task_id] >= POLL_RETRY_NUM) // give up after N retries
throw new Error('Unexpected response')
return retry({ task_id, headers, expect })
}
if (task_id in retries)
delete retries[task_id]
return response.data
Expand All @@ -36,21 +60,7 @@ const pollTaskStatus = ({ task_id, headers, grace_period = 0 }) => {
retries[task_id]++
if (retries[task_id] >= POLL_RETRY_NUM) // give up after N retries
throw error
return new Promise((resolve, reject) => {
setTimeout(() => { // debounce retries
pollTaskStatus({ task_id, headers })
.then(resolve)
.catch(err => {
if (err.message) { // AxiosError
const data = i18n.t('{message}. No response after {timeout} seconds, gave up after {retries} retries.', { message: err.message, timeout: POLL_RETRY_NUM * POLL_RETRY_INTERVAL, retries: POLL_RETRY_NUM })
reject({ response: { data } })
}
else { // recursion
reject(error)
}
})
}, (POLL_RETRY_INTERVAL + grace_period) * 1E3)
})
return retry({ task_id, headers, expect })
}
})
}
Expand Down Expand Up @@ -92,10 +102,10 @@ const actions = {
})
})
},
pollTaskStatus: ({ dispatch }, { task_id, headers }) => {
return api.pollTaskStatus({ task_id, headers }).then(data => { // 'poll' returns immediately, or timeout after 15s
pollTaskStatus: ({ dispatch }, { task_id, headers, expect }) => {
return api.pollTaskStatus({ task_id, headers, expect }).then(data => { // 'poll' returns immediately, or timeout after 15s
if ('status' in data && data.status.toString() === '202') { // 202: in progress
return dispatch('pollTaskStatus', { task_id, headers, grace_period: POLL_GRACE_PERIOD }) // recurse
return dispatch('pollTaskStatus', { task_id, headers, expect }) // recurse
}
if ('error' in data) {
throw new Error(data.error.message)
Expand Down

0 comments on commit ac76ca0

Please sign in to comment.