Skip to content

Commit

Permalink
fix: added retry mechanism to attachment storage creation (in case sq…
Browse files Browse the repository at this point in the history
…lite locked), fixed tests
  • Loading branch information
titanism committed Nov 5, 2024
1 parent ed1f0c3 commit 186fd13
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 17 deletions.
43 changes: 31 additions & 12 deletions helpers/attachment-storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@

const { Buffer } = require('node:buffer');

const _ = require('lodash');
const intoStream = require('into-stream');
const ms = require('ms');
const pRetry = require('p-retry');
const pify = require('pify');
const revHash = require('rev-hash');
const _ = require('lodash');
const { Builder } = require('json-sql');

const WildDuckAttachmentStorage = require('wildduck/lib/attachment-storage');
Expand All @@ -30,6 +32,8 @@ const WildDuckAttachmentStorage = require('wildduck/lib/attachment-storage');
//

const Attachments = require('#models/attachments');
const logger = require('#helpers/logger');
const isRetryableError = require('#helpers/is-retryable-error');
const { syncConvertResult } = require('#helpers/mongoose-to-sqlite');

const builder = new Builder();
Expand Down Expand Up @@ -108,7 +112,28 @@ async function updateAttachments(attachmentIds, magic, session) {
}
}

async function createAttachment(instance, session, node, isRetry = false) {
async function retryCreateAttachment(...args) {
return pRetry(() => createAttachment.call(this, ...args), {
retries: 2,
minTimeout: ms('5s'),
async onFailedAttempt(error) {
// TODO: add fallback mechanism which returns existing unique attachment
if (error.message === 'UNIQUE constraint failed: Attachments.hash') {
error.isCodeBug = true;
throw error;
}

if (isRetryableError(error)) {
logger.fatal(error);
return;
}

throw error;
}
});
}

async function createAttachment(instance, session, node) {
const hex = await this.calculateHashPromise(node.body);
node.hash = revHash(Buffer.from(hex, 'hex'));
node.counter = 1;
Expand Down Expand Up @@ -169,14 +194,8 @@ async function createAttachment(instance, session, node, isRetry = false) {
node.instance = instance;
node.session = session;

try {
const attachment = Attachments.create(node);
return attachment;
} catch (err) {
if (err.message !== 'UNIQUE constraint failed: Attachments.hash' || isRetry)
throw err;
return createAttachment.call(this, instance, session, node, true);
}
const attachment = Attachments.create(node);
return attachment;
}

class AttachmentStorage {
Expand Down Expand Up @@ -218,8 +237,8 @@ class AttachmentStorage {
};
}

async create(instance, session, node, isRetry = false) {
return createAttachment.call(this, instance, session, node, isRetry);
async create(instance, session, node) {
return retryCreateAttachment.call(this, instance, session, node);
}

//
Expand Down
15 changes: 10 additions & 5 deletions helpers/wkd.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ const ms = require('ms');
const undici = require('undici');

const TimeoutError = require('./timeout-error');
const config = require('#config');

const DURATION = config.env === 'test' ? '5s' : '2s';

//
// NOTE: this uses `fetch` which is OK because
Expand All @@ -32,14 +35,16 @@ function WKD(resolver) {
const abortController = new AbortController();
const t = setTimeout(() => {
if (!abortController?.signal?.aborted)
abortController.abort(new TimeoutError(`${url} took longer than 2s`));
}, ms('2s'));
abortController.abort(
new TimeoutError(`${url} took longer than ${DURATION}`)
);
}, ms(DURATION));
const response = await undici.fetch(url, {
signal: abortController.signal,
dispatcher: new undici.Agent({
headersTimeout: ms('2s'),
connectTimeout: ms('2s'),
bodyTimeout: ms('2s'),
headersTimeout: ms(DURATION),
connectTimeout: ms(DURATION),
bodyTimeout: ms(DURATION),
connect: {
lookup(hostname, options, fn) {
resolver
Expand Down

0 comments on commit 186fd13

Please sign in to comment.