@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.
Files changed (3) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/package.json +3 -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.4...main
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.4",
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.1"
25
+ "soap": "^1.9.3"
26
26
  },
27
27
  "devDependencies": {
28
- "vitest": "^4.1.5",
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
- const client = await SOAP.createClientAsync(url, {
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
- retries: 3,
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)})`)