···6464 "avsc": "^5.7.7",
6565 "bcryptjs": "^2.4.3",
6666 "body-parser": "^1.20.2",
6767- "bullmq": "^3.16.2",
6767+ "bullmq": "^5.0.0",
6868 "cassandra-driver": "^4.8.0",
6969 "cls-hooked": "^4.2.2",
7070 "connect-pg-simple": "^7.0.0",
···160160 "//": "Use an override to remove the @types/restify dependency, b/c it conflicts w/ pino-http. And a fork of retry-axios that has fixed type defs for TS's new module resolution algorithm.",
161161 "overrides": {
162162 "@types/restify": "npm:pino@8.6.0",
163163- "msgpackr": "^1.11.2",
164163 "@googlemaps/google-maps-services-js@^3.3.16": {
165164 "retry-axios": "npm:@ethanresnick/retry-axios@2.6.1"
166165 },
+14-2
server/routes/reporting/submitReport.ts
···439439 await enqueueWithRetries();
440440 },
441441 );
442442- // Do nothing on error, as the span will already be marked as failed
443443- } catch {}
442442+ // Record on active span and log so we can diagnose when enqueue fails (e.g. no default queue, BullMQ/Redis errors)
443443+ } catch (e) {
444444+ const activeSpan = Tracer.getActiveSpan();
445445+ if (activeSpan?.isRecording()) {
446446+ activeSpan.recordException(e as Exception);
447447+ }
448448+ // eslint-disable-next-line no-console
449449+ console.error(
450450+ 'Failed to enqueue report to manual review queue',
451451+ reportId,
452452+ orgId,
453453+ e,
454454+ );
455455+ }
444456 // this error handling only triggers on errors before the `res.sendStatus` call
445457 } catch (e: unknown) {
446458 const activeSpan = Tracer.getActiveSpan();
···821821 const queue = await this.#getBullQueue(orgId, queueId);
822822 const { bullId } = parseExternalId(jobId);
823823 const job = await queue.getJob(bullId);
824824- await job?.update(data);
824824+ await job?.updateData(data);
825825826826 // Because the `data` arg above is a ManualReviewJob, we know the stored
827827 // data for this particular job won't be in the legacy format.
···13561356/**
13571357 * We want Bull to dedupe jobs on the same item, so this function maps each
13581358 * distinct item identifier object to a string that can be used as a Bull job id.
13591359+ * Uses '.' as separator because BullMQ v5 disallows ':' in custom job ids.
13591360 *
13601361 * NB: only exported for use in tests.
13611362 * @private
13621363 */
13641364+const BULL_JOB_ID_SEPARATOR = '.';
13651365+13631366export function itemIdToBullJobId({ typeId, id }: ItemIdentifier) {
13641367 if (!typeId || !id) {
13651368 throw new Error('itemTypeId and itemId cannot be empty strings');
13661369 }
1367137013681371 return instantiateOpaqueType<BullJobId>(
13691369- [typeId, id].map(b64UrlEncode).join(':'),
13721372+ [typeId, id].map(b64UrlEncode).join(BULL_JOB_ID_SEPARATOR),
13701373 );
13711374}
13721375