feat(xen-api): automatically retry ro calls on ECONNRESET (#5674)
See xoa-support#3266
This commit is contained in:
parent
2e0e1d2aac
commit
853905e52f
@ -13,6 +13,7 @@
|
||||
|
||||
- [Pool] Fix `an error has occurred` when using the "Disconnect" button from the pool page [#5669](https://github.com/vatesfr/xen-orchestra/issues/5669) (PR [#5671](https://github.com/vatesfr/xen-orchestra/pull/5671))
|
||||
- [Configuration] Automatically connect enabled servers after import [#5660](https://github.com/vatesfr/xen-orchestra/issues/5660) (PR [#5672](https://github.com/vatesfr/xen-orchestra/pull/5672))
|
||||
- Work-around some `ECONNRESET` errors when connecting to XEN-API (PR [#5674](https://github.com/vatesfr/xen-orchestra/pull/5674))
|
||||
|
||||
### Packages to release
|
||||
|
||||
@ -31,5 +32,6 @@
|
||||
>
|
||||
> In case of conflict, the highest (lowest in previous list) `$version` wins.
|
||||
|
||||
- xen-api minor
|
||||
- xo-server patch
|
||||
- xo-web patch
|
||||
|
@ -86,6 +86,13 @@ export class Xapi extends EventEmitter {
|
||||
this._readOnly = Boolean(opts.readOnly)
|
||||
this._RecordsByType = { __proto__: null }
|
||||
|
||||
this._roCallRetryOptions = {
|
||||
delay: 1e3,
|
||||
tries: 10,
|
||||
...opts.roCallRetryOptions,
|
||||
when: { code: 'ECONNRESET' },
|
||||
}
|
||||
|
||||
this._auth = opts.auth
|
||||
const url = parseUrl(opts.url)
|
||||
if (this._auth === undefined) {
|
||||
@ -231,7 +238,9 @@ export class Xapi extends EventEmitter {
|
||||
|
||||
// this should be used for instantaneous calls, otherwise use `callAsync`
|
||||
call(method, ...args) {
|
||||
return this._readOnly && !isReadOnlyCall(method, args)
|
||||
return isReadOnlyCall(method, args)
|
||||
? this._roCall(method, args)
|
||||
: this._readOnly
|
||||
? Promise.reject(new Error(`cannot call ${method}() in read only mode`))
|
||||
: this._sessionCall(method, args)
|
||||
}
|
||||
@ -261,15 +270,15 @@ export class Xapi extends EventEmitter {
|
||||
// ===========================================================================
|
||||
|
||||
async getAllRecords(type) {
|
||||
return map(await this._sessionCall(`${type}.get_all_records`), (record, ref) => this._wrapRecord(type, ref, record))
|
||||
return map(await this._roCall(`${type}.get_all_records`), (record, ref) => this._wrapRecord(type, ref, record))
|
||||
}
|
||||
|
||||
async getRecord(type, ref) {
|
||||
return this._wrapRecord(type, ref, await this._sessionCall(`${type}.get_record`, [ref]))
|
||||
return this._wrapRecord(type, ref, await this._roCall(`${type}.get_record`, [ref]))
|
||||
}
|
||||
|
||||
async getRecordByUuid(type, uuid) {
|
||||
return this.getRecord(type, await this._sessionCall(`${type}.get_by_uuid`, [uuid]))
|
||||
return this.getRecord(type, await this._roCall(`${type}.get_by_uuid`, [uuid]))
|
||||
}
|
||||
|
||||
getRecords(type, refs) {
|
||||
@ -277,7 +286,7 @@ export class Xapi extends EventEmitter {
|
||||
}
|
||||
|
||||
getField(type, ref, field) {
|
||||
return this._sessionCall(`${type}.get_${field}`, [ref])
|
||||
return this._roCall(`${type}.get_${field}`, [ref])
|
||||
}
|
||||
|
||||
setField(type, ref, field, value) {
|
||||
@ -849,7 +858,7 @@ export class Xapi extends EventEmitter {
|
||||
types.map(async type => {
|
||||
try {
|
||||
const toRemove = toRemoveByType[type]
|
||||
const records = await this._sessionCall(`${type}.get_all_records`)
|
||||
const records = await this._roCall(`${type}.get_all_records`)
|
||||
const refs = getKeys(records)
|
||||
refs.forEach(ref => {
|
||||
toRemove.delete(ref)
|
||||
@ -900,6 +909,11 @@ export class Xapi extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
// read-only call, automatically retry in case of connection issues
|
||||
_roCall(method, args) {
|
||||
return pRetry(() => this._sessionCall(method, args), this._roCallRetryOptions)
|
||||
}
|
||||
|
||||
_watchEvents = coalesceCalls(this._watchEvents)
|
||||
async _watchEvents() {
|
||||
// eslint-disable-next-line no-labels
|
||||
@ -1015,7 +1029,7 @@ export class Xapi extends EventEmitter {
|
||||
|
||||
try {
|
||||
await this._connected
|
||||
this._processEvents(await this._sessionCall('event.next', undefined, EVENT_TIMEOUT * 1e3))
|
||||
this._processEvents(await this._roCall('event.next', undefined, EVENT_TIMEOUT * 1e3))
|
||||
} catch (error) {
|
||||
if (error?.code === 'EVENTS_LOST') {
|
||||
await ignoreErrors.call(this._sessionCall('event.unregister', [types]))
|
||||
|
Loading…
Reference in New Issue
Block a user