@solidxai/core 0.1.6-beta.23 → 0.1.6-beta.25

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.
Files changed (82) hide show
  1. package/dist/entities/mq-message-queue.entity.d.ts.map +1 -1
  2. package/dist/entities/mq-message-queue.entity.js.map +1 -1
  3. package/dist/helpers/bootstrap.helper.js +1 -1
  4. package/dist/helpers/bootstrap.helper.js.map +1 -1
  5. package/dist/helpers/cors.helper.d.ts.map +1 -1
  6. package/dist/helpers/cors.helper.js +4 -1
  7. package/dist/helpers/cors.helper.js.map +1 -1
  8. package/dist/interfaces.d.ts +1 -0
  9. package/dist/interfaces.d.ts.map +1 -1
  10. package/dist/interfaces.js.map +1 -1
  11. package/dist/jobs/chatter-queue-options.js +1 -1
  12. package/dist/jobs/chatter-queue-options.js.map +1 -1
  13. package/dist/jobs/chatter-queue-publisher.service.d.ts +9 -9
  14. package/dist/jobs/chatter-queue-publisher.service.d.ts.map +1 -1
  15. package/dist/jobs/chatter-queue-publisher.service.js +5 -5
  16. package/dist/jobs/chatter-queue-publisher.service.js.map +1 -1
  17. package/dist/jobs/chatter-queue-subscriber.service.d.ts +4 -4
  18. package/dist/jobs/chatter-queue-subscriber.service.d.ts.map +1 -1
  19. package/dist/jobs/chatter-queue-subscriber.service.js +11 -11
  20. package/dist/jobs/chatter-queue-subscriber.service.js.map +1 -1
  21. package/dist/jobs/computed-field-evaluation-queue-options.d.ts +1 -0
  22. package/dist/jobs/computed-field-evaluation-queue-options.d.ts.map +1 -1
  23. package/dist/jobs/computed-field-evaluation-queue-options.js +1 -0
  24. package/dist/jobs/computed-field-evaluation-queue-options.js.map +1 -1
  25. package/dist/jobs/database/chatter-queue-options-database.d.ts +8 -0
  26. package/dist/jobs/database/chatter-queue-options-database.d.ts.map +1 -0
  27. package/dist/jobs/database/chatter-queue-options-database.js +10 -0
  28. package/dist/jobs/database/chatter-queue-options-database.js.map +1 -0
  29. package/dist/jobs/database/chatter-queue-publisher-database.service.d.ts +12 -0
  30. package/dist/jobs/database/chatter-queue-publisher-database.service.d.ts.map +1 -0
  31. package/dist/jobs/database/chatter-queue-publisher-database.service.js +39 -0
  32. package/dist/jobs/database/chatter-queue-publisher-database.service.js.map +1 -0
  33. package/dist/jobs/database/chatter-queue-subscriber-database.service.d.ts +19 -0
  34. package/dist/jobs/database/chatter-queue-subscriber-database.service.d.ts.map +1 -0
  35. package/dist/jobs/database/chatter-queue-subscriber-database.service.js +62 -0
  36. package/dist/jobs/database/chatter-queue-subscriber-database.service.js.map +1 -0
  37. package/dist/services/chatter-message.service.d.ts +4 -4
  38. package/dist/services/chatter-message.service.d.ts.map +1 -1
  39. package/dist/services/chatter-message.service.js +33 -9
  40. package/dist/services/chatter-message.service.js.map +1 -1
  41. package/dist/services/queues/rabbitmq-publisher.service.d.ts +1 -0
  42. package/dist/services/queues/rabbitmq-publisher.service.d.ts.map +1 -1
  43. package/dist/services/queues/rabbitmq-publisher.service.js +6 -1
  44. package/dist/services/queues/rabbitmq-publisher.service.js.map +1 -1
  45. package/dist/services/queues/rabbitmq-subscriber.service.d.ts +1 -0
  46. package/dist/services/queues/rabbitmq-subscriber.service.d.ts.map +1 -1
  47. package/dist/services/queues/rabbitmq-subscriber.service.js +15 -4
  48. package/dist/services/queues/rabbitmq-subscriber.service.js.map +1 -1
  49. package/dist/services/request-context.service.d.ts +2 -1
  50. package/dist/services/request-context.service.d.ts.map +1 -1
  51. package/dist/services/request-context.service.js.map +1 -1
  52. package/dist/solid-core.module.d.ts.map +1 -1
  53. package/dist/solid-core.module.js +8 -0
  54. package/dist/solid-core.module.js.map +1 -1
  55. package/dist/subscribers/audit.subscriber.d.ts +8 -3
  56. package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
  57. package/dist/subscribers/audit.subscriber.js +54 -52
  58. package/dist/subscribers/audit.subscriber.js.map +1 -1
  59. package/dist/subscribers/created-by-updated-by.subscriber.d.ts +0 -1
  60. package/dist/subscribers/created-by-updated-by.subscriber.d.ts.map +1 -1
  61. package/dist/subscribers/created-by-updated-by.subscriber.js +3 -13
  62. package/dist/subscribers/created-by-updated-by.subscriber.js.map +1 -1
  63. package/package.json +1 -1
  64. package/src/entities/mq-message-queue.entity.ts +8 -8
  65. package/src/helpers/bootstrap.helper.ts +1 -1
  66. package/src/helpers/cors.helper.ts +5 -1
  67. package/src/interfaces.ts +1 -0
  68. package/src/jobs/chatter-queue-options.ts +1 -1
  69. package/src/jobs/chatter-queue-publisher.service.ts +11 -11
  70. package/src/jobs/chatter-queue-subscriber.service.ts +13 -8
  71. package/src/jobs/computed-field-evaluation-queue-options.ts +1 -0
  72. package/src/jobs/database/chatter-queue-options-database.ts +9 -0
  73. package/src/jobs/database/chatter-queue-publisher-database.service.ts +24 -0
  74. package/src/jobs/database/chatter-queue-subscriber-database.service.ts +53 -0
  75. package/src/services/chatter-message.service.ts +41 -9
  76. package/src/services/queues/rabbitmq-publisher.service.ts +8 -2
  77. package/src/services/queues/rabbitmq-subscriber.service.ts +16 -5
  78. package/src/services/request-context.service.ts +2 -1
  79. package/src/solid-core.module.ts +8 -2
  80. package/src/subscribers/audit.subscriber.ts +59 -224
  81. package/src/subscribers/created-by-updated-by.subscriber.ts +22 -16
  82. package/logs_load_testing +0 -49
@@ -1,14 +1,14 @@
1
1
  import { CommonEntity } from "src/entities/common.entity"
2
- import {Entity, Column, OneToMany} from "typeorm";
2
+ import { Entity, Column, OneToMany } from "typeorm";
3
3
  import { MqMessage } from 'src/entities/mq-message.entity'
4
4
  @Entity("ss_mq_message_queue")
5
- export class MqMessageQueue extends CommonEntity{
6
- @Column({ type: "varchar", unique: true })
7
- name: string;
5
+ export class MqMessageQueue extends CommonEntity {
6
+ @Column({ type: "varchar", unique: true })
7
+ name: string;
8
8
 
9
- @Column({ type: "varchar", nullable: true })
10
- description: string;
9
+ @Column({ type: "varchar", nullable: true })
10
+ description: string;
11
11
 
12
- @OneToMany(() => MqMessage, mqMessage => mqMessage.mqMessageQueue, { cascade: true })
13
- mqMessages: MqMessage[];
12
+ @OneToMany(() => MqMessage, mqMessage => mqMessage.mqMessageQueue, { cascade: true })
13
+ mqMessages: MqMessage[];
14
14
  }
@@ -110,7 +110,7 @@ export async function bootstrapSolidApp(
110
110
  if (req.query) {
111
111
  req.query = qs.parse(req.url.split('?')[1], {
112
112
  allowDots: true,
113
- depth: 10,
113
+ depth: 20,
114
114
  arrayLimit: 100,
115
115
  });
116
116
  }
@@ -1,8 +1,10 @@
1
+ import { log } from 'console';
1
2
  import { CorsOptions } from 'cors';
2
3
 
3
4
  /** Build CorsOptions from env; supports wildcards like https://*.example.com */
4
5
  export function buildDefaultCorsOptions(): CorsOptions {
5
6
  const rawOrigins = process.env.SECURITY_CORS_ORIGINS ?? '*';
7
+ log(`CORS allowed origins: ${rawOrigins}`);
6
8
 
7
9
  const allowed = rawOrigins.split(',').map(s => s.trim()).filter(Boolean);
8
10
 
@@ -18,6 +20,8 @@ export function buildDefaultCorsOptions(): CorsOptions {
18
20
  };
19
21
 
20
22
  const matchers = allowed.map(patternToRegex);
23
+ log(`CORS regexes: ${matchers.map(r => r.toString()).join(', ')}`);
24
+
21
25
  const isAllowed = (origin: string) =>
22
26
  matchers.length > 0 && matchers.some(rx => rx.test(origin));
23
27
 
@@ -25,7 +29,7 @@ export function buildDefaultCorsOptions(): CorsOptions {
25
29
  origin: (origin, cb) => {
26
30
  if (!origin) return cb(null, true); // allow no-origin (CLI/mobile/internal)
27
31
  if (isAllowed(origin)) return cb(null, true);
28
- return cb(new Error(`Origin ${origin} not allowed by CORS`), false);
32
+ return cb(new Error(`Origin ${origin} not allowed by CORS. Allowed origins: ${allowed.join(', ')}`), false);
29
33
  },
30
34
  methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
31
35
  allowedHeaders: ['Content-Type', 'Authorization'],
package/src/interfaces.ts CHANGED
@@ -271,6 +271,7 @@ export interface QueuesModuleOptions {
271
271
  type: BrokerType;
272
272
  queueName: string;
273
273
  prefetch?: number;
274
+ persistToDatabase?: boolean;
274
275
  }
275
276
 
276
277
  export type MediaWithFullUrl = Media & {
@@ -1,6 +1,6 @@
1
1
  import { BrokerType } from "../interfaces";
2
2
 
3
- const QUEUE_NAME = 'solid_chatter_queue';
3
+ const QUEUE_NAME = 'solid_chatter_queue_rabbitmq';
4
4
 
5
5
  export default {
6
6
  name: QUEUE_NAME,
@@ -7,21 +7,21 @@ import { MqMessageService } from '../services/mq-message.service';
7
7
  import { QueuesModuleOptions } from "../interfaces";
8
8
 
9
9
 
10
- export type ChatterEventType = 'insert' | 'update' | 'delete';
10
+ export type AuditEventType = 'insert' | 'update' | 'delete';
11
11
 
12
- export interface ChatterMessagePayload {
13
- eventType: ChatterEventType;
14
- model: string; // entity name
15
- entityId: string; // id string
16
- occurredAt: string; // ISO
17
- before?: any;
18
- after?: any;
19
- diff?: string[]; // changed column names for updates
20
- userId?: string | null;
12
+ export interface AuditQueuePayload {
13
+ eventType: AuditEventType;
14
+ modelName: string; // TypeORM entity class name (e.g. 'Order')
15
+ entityId: string | number | null;
16
+ occurredAt: string; // ISO timestamp, captured at event time
17
+ after?: any; // entity state after operation (insert/update)
18
+ before?: any; // entity state before operation (update/delete)
19
+ updatedColumnNames?: string[]; // propertyNames of changed columns (update only)
20
+ userId?: number | null; // active user captured at event time
21
21
  }
22
22
 
23
23
  @Injectable()
24
- export class ChatterQueuePublisher extends RabbitMqPublisher<any> {
24
+ export class ChatterQueuePublisherRabbitmq extends RabbitMqPublisher<AuditQueuePayload> {
25
25
  constructor(
26
26
  protected readonly mqMessageService: MqMessageService,
27
27
  protected readonly mqMessageQueueService: MqMessageQueueService,
@@ -6,12 +6,12 @@ import { MqMessageService } from '../services/mq-message.service';
6
6
  import { MqMessageQueueService } from '../services/mq-message-queue.service';
7
7
  import { QueuesModuleOptions } from "../interfaces";
8
8
  import chatterQueueOptions from './chatter-queue-options';
9
- import { ChatterMessagePayload } from './chatter-queue-publisher.service';
9
+ import { AuditQueuePayload } from './chatter-queue-publisher.service';
10
10
  import { ChatterMessageService } from 'src/services/chatter-message.service';
11
11
 
12
12
  @Injectable()
13
- export class ChatterQueueSubscriber extends RabbitMqSubscriber<any> {
14
- private readonly chatterQueueLogger = new Logger(ChatterQueueSubscriber.name);
13
+ export class ChatterQueueSubscriberRabbitmq extends RabbitMqSubscriber<AuditQueuePayload> {
14
+ private readonly chatterLogger = new Logger(ChatterQueueSubscriberRabbitmq.name);
15
15
 
16
16
  constructor(
17
17
  readonly mqMessageService: MqMessageService,
@@ -27,19 +27,24 @@ export class ChatterQueueSubscriber extends RabbitMqSubscriber<any> {
27
27
  }
28
28
  }
29
29
 
30
- async subscribe(message: QueueMessage<ChatterMessagePayload>) {
30
+ async subscribe(message: QueueMessage<AuditQueuePayload>) {
31
31
  const p = message.payload;
32
- this.chatterQueueLogger.debug(`Audit event ${p.eventType} ${p.model}#${p.entityId}`);
32
+ this.chatterLogger.debug(`Audit event ${p.eventType} ${p.modelName}#${p.entityId}`);
33
33
 
34
34
  switch (p.eventType) {
35
35
  case 'insert':
36
- await this.chatterMessageService.postAuditMessageOnInsert(p.after, { name: p.model } as any);
36
+ await this.chatterMessageService.postAuditMessageOnInsert(p.after, p.modelName);
37
37
  break;
38
38
  case 'update':
39
- await this.chatterMessageService.postAuditMessageOnUpdate(p.after, { name: p.model } as any, p.before, (p.diff || []).map(n => ({ propertyName: n })));
39
+ await this.chatterMessageService.postAuditMessageOnUpdate(
40
+ p.after,
41
+ p.modelName,
42
+ p.before,
43
+ (p.updatedColumnNames ?? []).map(n => ({ propertyName: n })),
44
+ );
40
45
  break;
41
46
  case 'delete':
42
- await this.chatterMessageService.postAuditMessageOnDelete(p.before, { name: p.model } as any, p.before);
47
+ await this.chatterMessageService.postAuditMessageOnDelete(p.modelName, p.before);
43
48
  break;
44
49
  }
45
50
  }
@@ -7,4 +7,5 @@ export default {
7
7
  type: BrokerType.RabbitMQ,
8
8
  queueName: QUEUE_NAME,
9
9
  prefetch: 10,
10
+ persistToDatabase: false,
10
11
  };
@@ -0,0 +1,9 @@
1
+ import { BrokerType } from "../../interfaces";
2
+
3
+ const QUEUE_NAME = 'solid_chatter_queue_database';
4
+
5
+ export default {
6
+ name: QUEUE_NAME,
7
+ type: BrokerType.Database,
8
+ queueName: QUEUE_NAME,
9
+ };
@@ -0,0 +1,24 @@
1
+ import { Injectable } from '@nestjs/common';
2
+
3
+ import { DatabasePublisher } from 'src/services/queues/database-publisher.service';
4
+ import { MqMessageQueueService } from '../../services/mq-message-queue.service';
5
+ import { MqMessageService } from '../../services/mq-message.service';
6
+ import { QueuesModuleOptions } from "../../interfaces";
7
+ import { AuditQueuePayload } from '../chatter-queue-publisher.service';
8
+ import chatterQueueOptionsDatabase from './chatter-queue-options-database';
9
+
10
+ @Injectable()
11
+ export class ChatterQueuePublisherDatabase extends DatabasePublisher<AuditQueuePayload> {
12
+ constructor(
13
+ protected readonly mqMessageService: MqMessageService,
14
+ protected readonly mqMessageQueueService: MqMessageQueueService,
15
+ ) {
16
+ super(mqMessageService, mqMessageQueueService);
17
+ }
18
+
19
+ options(): QueuesModuleOptions {
20
+ return {
21
+ ...chatterQueueOptionsDatabase
22
+ };
23
+ }
24
+ }
@@ -0,0 +1,53 @@
1
+ import { Injectable, Logger } from '@nestjs/common';
2
+
3
+ import { DatabaseSubscriber } from 'src/services/queues/database-subscriber.service';
4
+ import { QueueMessage } from 'src/interfaces/mq';
5
+ import { MqMessageService } from '../../services/mq-message.service';
6
+ import { MqMessageQueueService } from '../../services/mq-message-queue.service';
7
+ import { QueuesModuleOptions } from "../../interfaces";
8
+ import { PollerService } from 'src/services/poller.service';
9
+ import { AuditQueuePayload } from '../chatter-queue-publisher.service';
10
+ import { ChatterMessageService } from 'src/services/chatter-message.service';
11
+ import chatterQueueOptionsDatabase from './chatter-queue-options-database';
12
+
13
+ @Injectable()
14
+ export class ChatterQueueSubscriberDatabase extends DatabaseSubscriber<AuditQueuePayload> {
15
+ private readonly chatterLogger = new Logger(ChatterQueueSubscriberDatabase.name);
16
+
17
+ constructor(
18
+ readonly mqMessageService: MqMessageService,
19
+ readonly mqMessageQueueService: MqMessageQueueService,
20
+ readonly poller: PollerService,
21
+ private readonly chatterMessageService: ChatterMessageService,
22
+ ) {
23
+ super(mqMessageService, mqMessageQueueService, poller);
24
+ }
25
+
26
+ options(): QueuesModuleOptions {
27
+ return {
28
+ ...chatterQueueOptionsDatabase
29
+ };
30
+ }
31
+
32
+ async subscribe(message: QueueMessage<AuditQueuePayload>) {
33
+ const p = message.payload;
34
+ this.chatterLogger.debug(`Audit event ${p.eventType} ${p.modelName}#${p.entityId}`);
35
+
36
+ switch (p.eventType) {
37
+ case 'insert':
38
+ await this.chatterMessageService.postAuditMessageOnInsert(p.after, p.modelName);
39
+ break;
40
+ case 'update':
41
+ await this.chatterMessageService.postAuditMessageOnUpdate(
42
+ p.after,
43
+ p.modelName,
44
+ p.before,
45
+ (p.updatedColumnNames ?? []).map(n => ({ propertyName: n })),
46
+ );
47
+ break;
48
+ case 'delete':
49
+ await this.chatterMessageService.postAuditMessageOnDelete(p.modelName, p.before);
50
+ break;
51
+ }
52
+ }
53
+ }
@@ -90,13 +90,13 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
90
90
  return savedMessage;
91
91
  }
92
92
 
93
- async postAuditMessageOnInsert(entity: any, metadata: EntityMetadata, messageQueue: boolean = false) {
93
+ async postAuditMessageOnInsert(entity: any, modelName: string, messageQueue: boolean = false) {
94
94
  if (!entity) {
95
95
  return;
96
96
  }
97
97
  const model = await this.modelMetadataRepo.findOne({
98
98
  where: {
99
- singularName: lowerFirst(metadata.name)
99
+ singularName: lowerFirst(modelName)
100
100
  },
101
101
  relations: {
102
102
  fields: true,
@@ -152,13 +152,13 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
152
152
  }
153
153
  }
154
154
 
155
- async postAuditMessageOnUpdate(entity: any, metadata: EntityMetadata, databaseEntity: any, updatedColumns: any[] = [], messageQueue: boolean = false) {
155
+ async postAuditMessageOnUpdate(entity: any, modelName: string, databaseEntity: any, updatedColumns: any[] = [], messageQueue: boolean = false) {
156
156
  if (!databaseEntity || !entity) {
157
157
  return;
158
158
  }
159
159
  const model = await this.modelMetadataRepo.findOne({
160
160
  where: {
161
- singularName: lowerFirst(metadata.name)
161
+ singularName: lowerFirst(modelName)
162
162
  },
163
163
  relations: {
164
164
  fields: true,
@@ -204,6 +204,7 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
204
204
 
205
205
  const changedRelationFields = [];
206
206
  if (potentialRelationFields.length > 0) {
207
+ const metadata = this.entityManager.connection.entityMetadatas.find(m => m.name === modelName);
207
208
  const populatedOldEntity = await this.populateRelationFields(databaseEntity, potentialRelationFields, metadata);
208
209
 
209
210
  for (const field of potentialRelationFields) {
@@ -268,13 +269,12 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
268
269
  }
269
270
  }
270
271
 
271
- async postAuditMessageOnDelete(entity: any, metadata: EntityMetadata, databaseEntity: any, messageQueue: boolean = false) {
272
+ async postAuditMessageOnDelete(modelName: string, databaseEntity: any, messageQueue: boolean = false) {
272
273
  const model = await this.modelMetadataRepo.findOne({
273
274
  where: {
274
- singularName: lowerFirst(metadata.name)
275
+ singularName: lowerFirst(modelName)
275
276
  },
276
277
  relations: {
277
- fields: true,
278
278
  module: true,
279
279
  userKeyField: true
280
280
  }
@@ -284,13 +284,29 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
284
284
  return;
285
285
  }
286
286
 
287
+ const modelFields = await this.modelMetadataHelperService.loadFieldHierarchy(model.singularName);
288
+
289
+ const auditFields = modelFields.filter(field =>
290
+ field.enableAuditTracking &&
291
+ !['mediaSingle', 'mediaMultiple', 'richText', 'json'].includes(field.type) &&
292
+ !(field.type === 'relation' && field.relationType === 'one-to-many')
293
+ );
294
+
295
+ // Populate relation fields so display values (e.g. names) are resolvable.
296
+ // The related entities themselves still exist in the DB after a delete.
297
+ const relationFields = auditFields.filter(field => field.type === 'relation');
298
+ const entityMetadata = this.entityManager.connection.entityMetadatas.find(m => m.name === modelName);
299
+ const populatedEntity = relationFields.length > 0 && entityMetadata
300
+ ? await this.populateRelationFields(databaseEntity, relationFields, entityMetadata)
301
+ : { ...databaseEntity };
302
+
287
303
  const chatterMessage = new ChatterMessage();
288
304
  chatterMessage.messageType = CHATTER_MESSAGE_TYPE.AUDIT;
289
305
  chatterMessage.messageSubType = CHATTER_MESSAGE_SUBTYPE.AUDIT_DELETE;
290
306
  chatterMessage.coModelEntityId = databaseEntity?.id;
291
307
  chatterMessage.coModelName = model?.singularName;
292
308
  chatterMessage.modelDisplayName = model?.displayName;
293
- chatterMessage.modelUserKey = entity[model?.userKeyField?.name];
309
+ chatterMessage.modelUserKey = databaseEntity[model?.userKeyField?.name];
294
310
  chatterMessage.messageBody = `${model?.displayName} deleted`;
295
311
 
296
312
  const activeUser = this.requestContextService.getActiveUser();
@@ -302,7 +318,23 @@ export class ChatterMessageService extends CRUDService<ChatterMessage> {
302
318
  chatterMessage.user = null;
303
319
  }
304
320
 
305
- await this.repo.save(chatterMessage);
321
+ const savedMessage = await this.repo.save(chatterMessage);
322
+
323
+ for (const field of auditFields) {
324
+ const fieldValue = populatedEntity[field.name];
325
+ if (fieldValue !== undefined && fieldValue !== null && fieldValue !== '') {
326
+ const messageDetail = new ChatterMessageDetails();
327
+ messageDetail.chatterMessage = savedMessage;
328
+ messageDetail.fieldName = field.name;
329
+ messageDetail.fieldDisplayName = field.displayName;
330
+ messageDetail.fieldType = field.type;
331
+ messageDetail.oldValue = this.formatFieldValue(field, fieldValue);
332
+ messageDetail.oldValueDisplay = await this.formatFieldValueDisplay(field, fieldValue);
333
+ messageDetail.newValue = null;
334
+ messageDetail.newValueDisplay = null;
335
+ await this.chatterMessageDetailsRepo.save(messageDetail);
336
+ }
337
+ }
306
338
  }
307
339
 
308
340
  private formatFieldValue(field: any, value: any): string {
@@ -34,6 +34,10 @@ export abstract class RabbitMqPublisher<T> implements OnModuleDestroy, QueuePubl
34
34
 
35
35
  abstract options(): QueuesModuleOptions;
36
36
 
37
+ protected shouldPersistToDatabase(): boolean {
38
+ return this.options().persistToDatabase ?? true;
39
+ }
40
+
37
41
  private async ensureConnectionAndChannel(): Promise<amqp.Channel> {
38
42
  if (this.channel) {
39
43
  return this.channel;
@@ -170,7 +174,9 @@ export abstract class RabbitMqPublisher<T> implements OnModuleDestroy, QueuePubl
170
174
  message.messageId = uuidv4();
171
175
 
172
176
  // Save the message to the DB so that we can then change its status in the subscriber...
173
- await this.persistToDatabase(namespacedQueueName, message);
177
+ if (this.shouldPersistToDatabase()) {
178
+ await this.persistToDatabase(namespacedQueueName, message);
179
+ }
174
180
 
175
181
  // wait for the channel to confirm
176
182
  try {
@@ -199,7 +205,7 @@ export abstract class RabbitMqPublisher<T> implements OnModuleDestroy, QueuePubl
199
205
 
200
206
  private async persistToDatabase(queueName: string, message: QueueMessage<T>) {
201
207
 
202
- // TODO: make an entry in the relevant database table, generate a unique id earlier.
208
+ // make an entry in the relevant database table, generate a unique id earlier.
203
209
  try {
204
210
  // 1. resolve the queue first
205
211
  const mqMessageQueue = await this.mqMessageQueueService.resolveQueue(queueName);
@@ -56,6 +56,10 @@ export abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscr
56
56
 
57
57
  abstract options(): QueuesModuleOptions;
58
58
 
59
+ protected shouldPersistToDatabase(): boolean {
60
+ return this.options().persistToDatabase ?? true;
61
+ }
62
+
59
63
  async establishConnection(): Promise<amqp.Connection> {
60
64
 
61
65
  const url = new URL(this.url);
@@ -236,7 +240,9 @@ export abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscr
236
240
  this.logger.error(`Error processing message on queue ${queueName}: ${errorMessage}`, (error as Error)?.stack);
237
241
 
238
242
  if (message.currentRetry < message.retryCount) {
239
- await this.updateStatusInDatabase('retrying', message);
243
+ if (this.shouldPersistToDatabase()) {
244
+ await this.updateStatusInDatabase('retrying', message);
245
+ }
240
246
 
241
247
  message.currentRetry++;
242
248
  const retryQueue = `${queueName}.retry`;
@@ -254,8 +260,9 @@ export abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscr
254
260
  this.logger.warn(`Retrying message (${message.currentRetry}/${message.retryCount}) after ${message.retryInterval}ms on queue ${queueName}`);
255
261
  return;
256
262
  }
257
-
258
- await this.updateStatusInDatabase('failed', message, errorMessage, '');
263
+ if (this.shouldPersistToDatabase()) {
264
+ await this.updateStatusInDatabase('failed', message, errorMessage, '');
265
+ }
259
266
  channel.ack(rawMessage);
260
267
  await this.publishToFailedQueue(queueName, Buffer.from(JSON.stringify(message)), channel, error);
261
268
  this.logger.error(`Message failed after ${message.retryCount} attempts on queue ${queueName}: ${errorMessage}`);
@@ -355,7 +362,9 @@ export abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscr
355
362
  * Abstract method for message processing logic.
356
363
  */
357
364
  protected async processMessage(message: QueueMessage<T>, rawMessage, channel, queueName: string): Promise<void> {
358
- await this.updateStatusInDatabase('started', message);
365
+ if (this.shouldPersistToDatabase()) {
366
+ await this.updateStatusInDatabase('started', message);
367
+ }
359
368
 
360
369
  // Capture the results of handling the task.
361
370
  const result = await this.subscribeWithTimeout(message, queueName);
@@ -364,7 +373,9 @@ export abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscr
364
373
  channel.ack(rawMessage);
365
374
 
366
375
  // Persist success output and timing.
367
- await this.updateStatusInDatabase('succeeded', message, '', result ? JSON.stringify(result, null, 2) : '');
376
+ if (this.shouldPersistToDatabase()) {
377
+ await this.updateStatusInDatabase('succeeded', message, '', result ? JSON.stringify(result, null, 2) : '');
378
+ }
368
379
 
369
380
  }
370
381
 
@@ -2,6 +2,7 @@ import { Injectable } from "@nestjs/common";
2
2
  import { ClsService } from "nestjs-cls";
3
3
  import { REQUEST_USER_KEY } from "src/constants";
4
4
  import { BasicFilterDto } from "src/dtos/basic-filters.dto";
5
+ import { ActiveUserData } from "src/interfaces/active-user-data.interface";
5
6
 
6
7
  @Injectable()
7
8
  export class RequestContextService {
@@ -9,7 +10,7 @@ export class RequestContextService {
9
10
  }
10
11
 
11
12
  // This method i.e getActiveUser() will fetch the user from the request object in the context
12
- getActiveUser() {
13
+ getActiveUser(): ActiveUserData | undefined {
13
14
  return this.cls.get(REQUEST_USER_KEY);
14
15
  }
15
16
 
@@ -94,6 +94,10 @@ import { Msg91SmsQueuePublisher } from './jobs/msg91-sms-publisher.service';
94
94
  import { Msg91SmsQueueSubscriber } from './jobs/msg91-sms-subscriber.service';
95
95
  import { SmtpEmailQueuePublisherRabbitmq } from './jobs/smtp-email-publisher.service';
96
96
  import { SmtpEmailQueueSubscriberRabbitmq } from './jobs/smtp-email-subscriber.service';
97
+ import { ChatterQueuePublisherRabbitmq } from './jobs/chatter-queue-publisher.service';
98
+ import { ChatterQueueSubscriberRabbitmq } from './jobs/chatter-queue-subscriber.service';
99
+ import { ChatterQueuePublisherDatabase } from './jobs/database/chatter-queue-publisher-database.service';
100
+ import { ChatterQueueSubscriberDatabase } from './jobs/database/chatter-queue-subscriber-database.service';
97
101
  import { TestQueuePublisher } from './jobs/test-queue-publisher.service';
98
102
  import { TestQueueSubscriber } from './jobs/test-queue-subscriber.service';
99
103
  import { UserRegistrationListener } from './listeners/user-registration.listener';
@@ -595,8 +599,10 @@ import { Entity } from 'typeorm';
595
599
  TestQueuePublisher,
596
600
  TestQueueSubscriber,
597
601
 
598
- // ChatterQueuePublisher,
599
- // ChatterQueueSubscriber,
602
+ ChatterQueuePublisherRabbitmq,
603
+ ChatterQueueSubscriberRabbitmq,
604
+ ChatterQueuePublisherDatabase,
605
+ ChatterQueueSubscriberDatabase,
600
606
 
601
607
  TestQueuePublisherDatabase,
602
608
  TestQueueSubscriberDatabase,