From 3bb7d2c2944749c22c8649f3ca6983a77ad03459 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Tue, 30 Mar 2021 14:21:19 +0200 Subject: [PATCH] feat(xapi/call{,Async}): retry if too many pending tasks Logic from xo-server/xapi/call --- @xen-orchestra/xapi/src/index.js | 29 +++++++++++++++++++++++++++- CHANGELOG.unreleased.md | 3 +++ packages/xo-server/src/xapi/index.js | 14 -------------- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/@xen-orchestra/xapi/src/index.js b/@xen-orchestra/xapi/src/index.js index 9745d7347..373a73654 100644 --- a/@xen-orchestra/xapi/src/index.js +++ b/@xen-orchestra/xapi/src/index.js @@ -1,5 +1,6 @@ const assert = require('assert') const defer = require('promise-toolbox/defer') +const pRetry = require('promise-toolbox/retry') const { utcFormat, utcParse } = require('d3-time-format') const { Xapi: Base } = require('xen-api') @@ -34,10 +35,22 @@ const hasProps = o => { } class Xapi extends Base { - constructor({ ignoreNobakVdis, maxUncoalescedVdis, vdiDestroyRetryWhenInUse, ...opts }) { + constructor({ + callRetryWhenTooManyPendingTasks, + ignoreNobakVdis, + maxUncoalescedVdis, + vdiDestroyRetryWhenInUse, + ...opts + }) { assert.notStrictEqual(ignoreNobakVdis, undefined) super(opts) + this._callRetryWhenTooManyPendingTasks = { + delay: 5e3, + tries: 10, + ...callRetryWhenTooManyPendingTasks, + when: { code: 'TOO_MANY_PENDING_TASKS' }, + } this._ignoreNobakVdis = ignoreNobakVdis this._maxUncoalescedVdis = maxUncoalescedVdis this._vdiDestroyRetryWhenInUse = { @@ -124,3 +137,17 @@ mixin({ VM: require('./vm'), }) exports.Xapi = Xapi + +// TODO: remove once using next promise-toolbox +function pRetryWrap(fn, options) { + const getOptions = typeof options !== 'function' ? () => options : options + return function () { + return pRetry.call(() => fn.apply(this, arguments), getOptions.apply(this, arguments)) + } +} + +function getCallRetryOpts() { + return this._callRetryWhenTooManyPendingTasks +} +Xapi.prototype.call = pRetryWrap(Xapi.prototype.call, getCallRetryOpts) +Xapi.prototype.callAsync = pRetryWrap(Xapi.prototype.callAsync, getCallRetryOpts) diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 61d2b98c4..3c1517eb5 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -23,3 +23,6 @@ > - major: if the change breaks compatibility > > In case of conflict, the highest (lowest in previous list) `$version` wins. + +- @xen-orchestra/xapi minor +- xo-server patch diff --git a/packages/xo-server/src/xapi/index.js b/packages/xo-server/src/xapi/index.js index ded444692..6daf49ce0 100644 --- a/packages/xo-server/src/xapi/index.js +++ b/packages/xo-server/src/xapi/index.js @@ -126,20 +126,6 @@ export default class Xapi extends XapiBase { this.objects.on('update', onAddOrUpdate) } - call(...args) { - const fn = super.call - - const loop = () => - fn.apply(this, args)::pCatch( - { - code: 'TOO_MANY_PENDING_TASKS', - }, - () => pDelay(5e3).then(loop) - ) - - return loop() - } - // ================================================================= _registerGenericWatcher(fn) {