@open-xchange/soap-client 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -1
- package/package.json +3 -3
- package/soap.js +27 -5
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.1.5] - 2026-05-26
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Retry the WSDL fetch on transient network errors (ECONNRESET / ETIMEDOUT / etc.). The per-method `pRetry` wrapper was already handling SOAP method calls, but `SOAP.createClientAsync()` itself (which fetches the WSDL via axios under the hood) was unretried, so a single TLS hiccup during bootstrap would kill the whole test run.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Retry policy tuned to ride out a recovery window of up to ~3 minutes per call: 10 retries (11 attempts total) with exponential backoff from 1s up to 30s, capped, with jitter. Previous 3-retry / 10s-cap budget was useful for one-packet blips but ran out before a recovering service could come back. The same policy now applies to both the WSDL fetch and per-method SOAP calls (factored into a shared constant). Permanent SOAP faults (already-exists, auth failure, etc.) still abort immediately via `shouldAbortRetry`.
|
|
16
|
+
|
|
7
17
|
## [0.1.4] - 2026-05-21
|
|
8
18
|
|
|
9
19
|
### Fixed
|
|
@@ -103,7 +113,8 @@ All notable changes to this project will be documented in this file.
|
|
|
103
113
|
|
|
104
114
|
- Initial release: extract SOAP client into its own library
|
|
105
115
|
|
|
106
|
-
[unreleased]: https://gitlab.com/openxchange/appsuite/web-foundation/tools/-/compare/soap-client-0.1.
|
|
116
|
+
[unreleased]: https://gitlab.com/openxchange/appsuite/web-foundation/tools/-/compare/soap-client-0.1.5...main
|
|
117
|
+
[0.1.5]: https://gitlab.com/openxchange/appsuite/web-foundation/tools/-/compare/soap-client-0.1.4...soap-client-0.1.5
|
|
107
118
|
[0.1.4]: https://gitlab.com/openxchange/appsuite/web-foundation/tools/-/compare/soap-client-0.1.3...soap-client-0.1.4
|
|
108
119
|
[0.1.3]: https://gitlab.com/openxchange/appsuite/web-foundation/tools/-/compare/soap-client-0.1.2...soap-client-0.1.3
|
|
109
120
|
[0.1.2]: https://gitlab.com/openxchange/appsuite/web-foundation/tools/-/compare/soap-client-0.1.1...soap-client-0.1.2
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-xchange/soap-client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "SOAP client for OX App Suite",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"commander": "^14.0.3",
|
|
24
24
|
"p-retry": "^8.0.0",
|
|
25
|
-
"soap": "^1.9.
|
|
25
|
+
"soap": "^1.9.3"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"vitest": "^4.1.
|
|
28
|
+
"vitest": "^4.1.7",
|
|
29
29
|
"@open-xchange/lint": "0.3.0"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
package/soap.js
CHANGED
|
@@ -25,6 +25,21 @@ import pRetry, { AbortError as RetryAbortError } from 'p-retry'
|
|
|
25
25
|
// Set AbortError correctly
|
|
26
26
|
const AbortError = RetryAbortError
|
|
27
27
|
|
|
28
|
+
// Shared retry policy for both the WSDL fetch and per-method SOAP calls.
|
|
29
|
+
// Designed to ride out a service recovery window of up to ~3 minutes:
|
|
30
|
+
// fast retries for the first ~30s catch transient blips cheaply, then the
|
|
31
|
+
// schedule settles into 30s polling so a recovering service is picked up
|
|
32
|
+
// within one poll. Note: each pRetry cycle is independent, so back-to-back
|
|
33
|
+
// failures (WSDL + method) can spend up to ~6 minutes total — keep the CI
|
|
34
|
+
// job timeout above that or recovery won't be observable.
|
|
35
|
+
const RETRY_OPTIONS = {
|
|
36
|
+
retries: 10, // 11 attempts total
|
|
37
|
+
factor: 2, // exponential growth, doubling each attempt
|
|
38
|
+
minTimeout: 1000, // first wait = 1s
|
|
39
|
+
maxTimeout: 30000, // cap at 30s once growth exceeds it
|
|
40
|
+
randomize: true // jitter to avoid thundering herd across parallel shards
|
|
41
|
+
}
|
|
42
|
+
|
|
28
43
|
for (const envFile of ['.env', '.env.defaults']) {
|
|
29
44
|
try { process.loadEnvFile(envFile) } catch {}
|
|
30
45
|
}
|
|
@@ -213,13 +228,23 @@ async function createClientAsync (type) {
|
|
|
213
228
|
performance.mark(startMark)
|
|
214
229
|
const endpoint = `${provisioningUrl}/webservices/${type}`
|
|
215
230
|
const url = `${endpoint}/?wsdl`
|
|
216
|
-
|
|
231
|
+
// The WSDL fetch itself can hit transient network errors (ECONNRESET,
|
|
232
|
+
// ETIMEDOUT, ...). Without retry here, a single TLS hiccup during
|
|
233
|
+
// bootstrap kills the whole job before any per-method pRetry below has
|
|
234
|
+
// a chance to run.
|
|
235
|
+
const client = await pRetry(() => SOAP.createClientAsync(url, {
|
|
217
236
|
endpoint,
|
|
218
237
|
suppressStack: true,
|
|
219
238
|
wsdl_options: {
|
|
220
239
|
forever: true
|
|
221
240
|
},
|
|
222
241
|
gzip: true
|
|
242
|
+
}), {
|
|
243
|
+
...RETRY_OPTIONS,
|
|
244
|
+
onFailedAttempt: async error => {
|
|
245
|
+
if (shouldAbortRetry(error)) throw new AbortError(error)
|
|
246
|
+
console.log(`Retrying WSDL fetch (${type}) in ${error.retriesLeft} attempts (${describeError(error)})`)
|
|
247
|
+
}
|
|
223
248
|
})
|
|
224
249
|
|
|
225
250
|
// https://stackoverflow.com/questions/30740415/namespace-for-array-field-in-node-soap-client-node-js
|
|
@@ -246,10 +271,7 @@ async function createClientAsync (type) {
|
|
|
246
271
|
|
|
247
272
|
try {
|
|
248
273
|
const result = await pRetry(() => origMethod.apply(this, [soapOptions, { timeout: 30000, ...clientOptions }, ...args]), {
|
|
249
|
-
|
|
250
|
-
minTimeout: 1000, // Start with 1 second delay between retries
|
|
251
|
-
maxTimeout: 10000, // Cap retry delay at 10 seconds
|
|
252
|
-
randomize: true, // Add jitter to spread out concurrent retries
|
|
274
|
+
...RETRY_OPTIONS,
|
|
253
275
|
onFailedAttempt: async error => {
|
|
254
276
|
if (shouldAbortRetry(error)) throw new AbortError(error)
|
|
255
277
|
console.log(`Retrying ${String(prop)} in ${error.retriesLeft} attempts (${describeError(error)})`)
|