Skip to content

Commit

Permalink
fix(sandbox): fix serialization of error with circular references are…
Browse files Browse the repository at this point in the history
… present (#2815) fix #2813
  • Loading branch information
roggervalf authored Oct 12, 2024
1 parent 3980e75 commit a384d92
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 1 deletion.
16 changes: 15 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,14 +212,28 @@ export const parseObjectValues = (obj: {
return accumulator;
};

const getCircularReplacer = (rootReference: any) => {
const references = new WeakSet();
references.add(rootReference);
return (_: string, value: any) => {
if (typeof value === 'object' && value !== null) {
if (references.has(value)) {
return '[Circular]';
}
references.add(value);
}
return value;
};
};

export const errorToJSON = (value: any): Record<string, any> => {
const error: Record<string, any> = {};

Object.getOwnPropertyNames(value).forEach(function (propName: string) {
error[propName] = value[propName];
});

return error;
return JSON.parse(JSON.stringify(error, getCircularReplacer(value)));
};

const INFINITY = 1 / 0;
Expand Down
19 changes: 19 additions & 0 deletions tests/fixtures/fixture_processor_fail_with_circular_reference.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* A processor file to be used in tests.
*
*/
'use strict';

const delay = require('./delay');

module.exports = function (/*job*/) {
return delay(500).then(() => {
const error = new Error('error');
const value = {};
value.ref = value;
error.custom = value;
error.reference = error;

throw error;
});
};
42 changes: 42 additions & 0 deletions tests/test_sandboxed_process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,48 @@ function sandboxProcessTests(
await worker.close();
});

it('should process and fail when circular reference', async () => {
const processFile =
__dirname +
'/fixtures/fixture_processor_fail_with_circular_reference.js';

const worker = new Worker(queueName, processFile, {
connection,
prefix,
drainDelay: 1,
useWorkerThreads,
});

const failing = new Promise<void>((resolve, reject) => {
worker.on('failed', async (job, err) => {
try {
expect(job.data).eql({ foo: 'bar' });
expect(job.failedReason).eql('error');
expect(err.message).eql('error');
expect(err.stack).include(
'fixture_processor_fail_with_circular_reference.js',
);
expect(err.reference).to.equal('[Circular]');
expect(err.custom).to.deep.equal({ ref: '[Circular]' });
expect(Object.keys(worker['childPool'].retained)).to.have.lengthOf(
0,
);
expect(worker['childPool'].getAllFree()).to.have.lengthOf(1);

resolve();
} catch (err) {
reject(err);
}
});
});

await queue.add('test', { foo: 'bar' });

await failing;

await worker.close();
});

it('should error if processor file is missing', async () => {
let worker;
let didThrow = false;
Expand Down

0 comments on commit a384d92

Please sign in to comment.