@evanp/activitypub-bot 0.32.0 → 0.32.1

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.
@@ -4,7 +4,7 @@ import as2 from './activitystreams.js'
4
4
 
5
5
  export class DistributionWorker {
6
6
  static #QUEUE_ID = 'distribution'
7
- static #MAX_ATTEMPTS = 16
7
+ static #MAX_ATTEMPTS = 21 // ~24 days
8
8
  #jobQueue
9
9
  #client
10
10
  #logger
@@ -43,19 +43,35 @@ export class DistributionWorker {
43
43
  this.#logger.info({ jobId }, 'completed job')
44
44
  } catch (error) {
45
45
  if (!error.status) {
46
- this.#logger.error(`Could not deliver ${activity.id} to ${inbox}: ${error.message}`)
47
- this.#logger.error(error.stack)
46
+ this.#logger.warn(
47
+ { error, activity: activity.id, inbox },
48
+ 'Could not deliver activity and no HTTP status available')
49
+ await this.#jobQueue.fail(jobId, this.#workerId)
48
50
  } else if (error.status >= 300 && error.status < 400) {
49
- this.#logger.error(`Unexpected redirect code delivering ${activity.id} to ${inbox}: ${error.status} ${error.message}`)
51
+ this.#logger.warn(
52
+ { error, activity: activity.id, inbox },
53
+ 'Could not deliver activity and unexpected redirect code'
54
+ )
55
+ await this.#jobQueue.fail(jobId, this.#workerId)
50
56
  } else if (error.status >= 400 && error.status < 500) {
51
- this.#logger.error(`Bad request delivering ${activity.id} to ${inbox}: ${error.status} ${error.message}`)
57
+ this.#logger.warn(
58
+ { error, activity: activity.id, inbox },
59
+ 'Could not deliver activity due to client error'
60
+ )
61
+ await this.#jobQueue.fail(jobId, this.#workerId)
52
62
  } else if (error.status >= 500 && error.status < 600) {
53
63
  if (attempts >= DistributionWorker.#MAX_ATTEMPTS) {
54
- this.#logger.error(`Server error delivering ${activity.id} to ${inbox}: ${error.status} ${error.message}; giving up after ${attempts} attempts`)
55
- await this.#jobQueue.complete(jobId, this.#workerId)
64
+ this.#logger.warn(
65
+ { error, activity: activity.id, inbox, attempts },
66
+ 'Could not deliver activity due to server error; no more attempts'
67
+ )
68
+ await this.#jobQueue.fail(jobId, this.#workerId)
56
69
  } else {
57
70
  const delay = Math.round((2 ** (attempts - 1) * 1000) * (0.5 + Math.random()))
58
- this.#logger.warn(`Server error delivering ${activity.id} to ${inbox}: ${error.status} ${error.message}; will retry in ${delay} ms (${attempts} of ${DistributionWorker.#MAX_ATTEMPTS})`)
71
+ this.#logger.warn(
72
+ { error, activity: activity.id, inbox, attempts, delay },
73
+ 'Could not deliver activity due to server error; will retry'
74
+ )
59
75
  await this.#jobQueue.retryAfter(jobId, this.#workerId, delay)
60
76
  }
61
77
  }
package/lib/jobqueue.js CHANGED
@@ -157,6 +157,22 @@ export class JobQueue {
157
157
  this.#ac.abort()
158
158
  }
159
159
 
160
+ async fail (jobId, jobRunnerId) {
161
+ await this.#connection.query(`
162
+ INSERT INTO failed_job
163
+ (job_id, queue_id, priority, payload, claimed_at, claimed_by, attempts, retry_after, created_at, updated_at)
164
+ SELECT job_id, queue_id, priority, payload, claimed_at, claimed_by, attempts, retry_after, created_at, updated_at
165
+ FROM job
166
+ WHERE job_id = ?
167
+ AND claimed_by = ?;`,
168
+ { replacements: [jobId, jobRunnerId] })
169
+ await this.#connection.query(`
170
+ DELETE FROM job
171
+ WHERE job_id = ? AND claimed_by = ?;`,
172
+ { replacements: [jobId, jobRunnerId] })
173
+ this.#logger.debug({ method: 'complete', jobRunnerId, jobId }, 'completed job')
174
+ }
175
+
160
176
  async #countJobs (queueId) {
161
177
  this.#logger.debug({ method: '#countJobs', queueId }, 'checking queue size')
162
178
  const rows = await this.#connection.query(`
@@ -0,0 +1,21 @@
1
+ export const id = '006-failed-jobs'
2
+
3
+ export async function up (connection, queryOptions = {}) {
4
+ await connection.query(`
5
+ CREATE TABLE failed_job (
6
+ job_id char(21) NOT NULL PRIMARY KEY,
7
+ queue_id varchar(64) NOT NULL,
8
+ priority INTEGER,
9
+ payload TEXT,
10
+ claimed_at TIMESTAMP,
11
+ claimed_by varchar(64),
12
+ attempts INTEGER default 0,
13
+ retry_after TIMESTAMP,
14
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
15
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
16
+ );
17
+ `, queryOptions)
18
+ await connection.query(`
19
+ CREATE INDEX failed_job_queue_id on job (queue_id);
20
+ `, queryOptions)
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evanp/activitypub-bot",
3
- "version": "0.32.0",
3
+ "version": "0.32.1",
4
4
  "description": "server-side ActivityPub bot framework",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",