@evanp/activitypub-bot 0.32.1 → 0.32.3

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.
@@ -108,7 +108,11 @@ export class ActivityPubClient {
108
108
  if (res.status < 200 || res.status > 299) {
109
109
  const body = await res.text()
110
110
  this.#logger.warn({ status: res.status, body, url }, 'Could not fetch url')
111
- throw createHttpError(res.status, `Could not fetch ${url}`)
111
+ throw createHttpError(
112
+ res.status,
113
+ `Could not fetch ${url}`,
114
+ { headers: res.headers }
115
+ )
112
116
  }
113
117
  const contentType = res.headers.get('content-type')
114
118
  const mimeType = contentType?.split(';')[0].trim()
@@ -172,7 +176,11 @@ export class ActivityPubClient {
172
176
  await this.#limiter.update(hostname, res.headers)
173
177
  this.#logger.debug(`Done fetching POST for ${url}`)
174
178
  if (res.status < 200 || res.status > 299) {
175
- throw createHttpError(res.status, await res.text())
179
+ throw createHttpError(
180
+ res.status,
181
+ await res.text(),
182
+ { headers: res.headers }
183
+ )
176
184
  }
177
185
  }
178
186
 
@@ -58,22 +58,43 @@ export class DistributionWorker {
58
58
  { error, activity: activity.id, inbox },
59
59
  'Could not deliver activity due to client error'
60
60
  )
61
- await this.#jobQueue.fail(jobId, this.#workerId)
61
+ if ([408, 425, 429].includes(error.status)) {
62
+ this.#logger.debug(
63
+ { error, activity: activity.id, inbox },
64
+ 'Retrying on recoverable status'
65
+ )
66
+ const delay = this.#retryDelay(error.headers, attempts)
67
+ await this.#jobQueue.retryAfter(jobId, this.#workerId, delay)
68
+ } else {
69
+ await this.#jobQueue.fail(jobId, this.#workerId)
70
+ }
62
71
  } else if (error.status >= 500 && error.status < 600) {
63
- if (attempts >= DistributionWorker.#MAX_ATTEMPTS) {
72
+ if ([501, 505, 508, 510].includes(error.status)) {
73
+ this.#logger.warn(
74
+ { error, activity: activity.id, inbox, attempts },
75
+ 'Could not deliver activity due to unrecoverable server error'
76
+ )
77
+ await this.#jobQueue.fail(jobId, this.#workerId)
78
+ } else if (attempts >= DistributionWorker.#MAX_ATTEMPTS) {
64
79
  this.#logger.warn(
65
80
  { error, activity: activity.id, inbox, attempts },
66
81
  'Could not deliver activity due to server error; no more attempts'
67
82
  )
68
83
  await this.#jobQueue.fail(jobId, this.#workerId)
69
84
  } else {
70
- const delay = Math.round((2 ** (attempts - 1) * 1000) * (0.5 + Math.random()))
85
+ const delay = this.#retryDelay(error.headers, attempts)
71
86
  this.#logger.warn(
72
87
  { error, activity: activity.id, inbox, attempts, delay },
73
88
  'Could not deliver activity due to server error; will retry'
74
89
  )
75
90
  await this.#jobQueue.retryAfter(jobId, this.#workerId, delay)
76
91
  }
92
+ } else {
93
+ this.#logger.warn(
94
+ { error, activity: activity.id, inbox },
95
+ 'Could not deliver activity due to unexpected status range'
96
+ )
97
+ await this.#jobQueue.fail(jobId, this.#workerId)
77
98
  }
78
99
  }
79
100
  } catch (err) {
@@ -83,12 +104,31 @@ export class DistributionWorker {
83
104
  }
84
105
  this.#logger.warn({ err, jobId }, 'Error delivering to bot')
85
106
  if (jobId) {
86
- await this.#jobQueue.release(jobId, this.#workerId)
107
+ const delay = this.#retryDelay(null, attempts ?? 1)
108
+ this.#logger.warn(
109
+ { err, jobId, attempts, delay },
110
+ 'Retrying job after a delay'
111
+ )
112
+ await this.#jobQueue.retryAfter(jobId, this.#workerId, delay)
87
113
  }
88
114
  }
89
115
  }
90
116
  }
91
117
 
118
+ #retryDelay (headers, attempts) {
119
+ if (headers?.['retry-after']) {
120
+ this.#logger.debug('using retry-after header')
121
+ const retryAfter = headers['retry-after']
122
+ if (/^\d+$/.test(retryAfter)) {
123
+ return parseInt(retryAfter, 10) * 1000
124
+ } else {
125
+ return new Date(retryAfter) - Date.now()
126
+ }
127
+ }
128
+ this.#logger.debug('exponential backoff')
129
+ return Math.round((2 ** (attempts - 1) * 1000) * (0.5 + Math.random()))
130
+ }
131
+
92
132
  stop () {
93
133
  this.#running = false
94
134
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evanp/activitypub-bot",
3
- "version": "0.32.1",
3
+ "version": "0.32.3",
4
4
  "description": "server-side ActivityPub bot framework",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",