3ca4a11ca3
* feat: basic notification listener sturcuture * feat: clean up generated gql * chore: edited structure * feat: added basic repo * feat: ported comment email to job queue * feat: ported stream access request accepted * feat: added notification insertion * fix: minor typings * feat: delayed notifications * updated types * feat: fixed gql * notifications are listed * index on notifications * feat: while loop skiping for update locked * delayed notification for access request * take into account user prefrences * on comment view, notification is marked as read * feat: added gql notifications * feat: avoid raising errors * fix: error added scopes * fix: mr comments * fix: cursor and service method * feat: added stronger types to notifications and versioning logic * minor: rows updated
103 lines
3.3 KiB
TypeScript
103 lines
3.3 KiB
TypeScript
import { UninitializedResourceAccessError } from '@/modules/shared/errors'
|
|
import type { Optional } from '@/modules/shared/helpers/typeHelper'
|
|
import { getRedisUrl, isProdEnv, isTestEnv } from '@/modules/shared/helpers/envHelper'
|
|
import type Bull from 'bull'
|
|
import { initializeQueue as setupQueue } from '@speckle/shared/queue'
|
|
import { TIME_MS } from '@speckle/shared'
|
|
import type { NotificationEvents } from '@/modules/notifications/events/notificationListener'
|
|
import { notificationsLogger, Observability } from '@/observability/logging'
|
|
import { UnhandledNotificationError } from '@/modules/notifications/errors'
|
|
import CreatedOrUpdatedCommentHandler from '@/modules/notifications/services/events/handlers/createdOrUpdatedComment'
|
|
import StreamAccessRequestCreatedHandler from '@/modules/notifications/services/events/handlers/streamAccessRequestCreated'
|
|
import StreamAccessRequestFinalizedHandler from '@/modules/notifications/services/events/handlers/streamAccessRequestFinalized'
|
|
import { CommentEvents } from '@/modules/comments/domain/events'
|
|
import { AccessRequestEvents } from '@/modules/accessrequests/domain/events'
|
|
|
|
export const NOTIFICATION_EVENTS_QUEUE = 'default:user-event-notifications'
|
|
|
|
let queue: Optional<Bull.Queue>
|
|
|
|
export const buildNotificationEventsQueue = async (queueName: string) =>
|
|
await setupQueue({
|
|
queueName,
|
|
redisUrl: getRedisUrl(),
|
|
options: {
|
|
...(!isTestEnv()
|
|
? {
|
|
limiter: {
|
|
max: 10,
|
|
duration: TIME_MS.second
|
|
}
|
|
}
|
|
: {}),
|
|
defaultJobOptions: {
|
|
attempts: 1,
|
|
timeout: 10 * TIME_MS.second,
|
|
removeOnComplete: isProdEnv(),
|
|
removeOnFail: isProdEnv()
|
|
}
|
|
}
|
|
})
|
|
|
|
export function getQueue(): Bull.Queue {
|
|
if (!queue) {
|
|
throw new UninitializedResourceAccessError(
|
|
'Attempting to use uninitialized Bull queue'
|
|
)
|
|
}
|
|
|
|
return queue
|
|
}
|
|
|
|
export async function initializeNotificationEventsQueue() {
|
|
queue = await buildNotificationEventsQueue(NOTIFICATION_EVENTS_QUEUE)
|
|
}
|
|
|
|
export async function initializeNotificationEventsConsumption() {
|
|
const queue = getQueue()
|
|
|
|
void queue.process(async ({ data: event }: Bull.Job<NotificationEvents>) => {
|
|
const notificationLogger = Observability.extendLoggerComponent(
|
|
notificationsLogger,
|
|
event.eventName
|
|
)
|
|
|
|
try {
|
|
notificationLogger.info('Handling notifications for event')
|
|
|
|
switch (event.eventName) {
|
|
case CommentEvents.Created:
|
|
case CommentEvents.Updated:
|
|
await CreatedOrUpdatedCommentHandler(event)
|
|
break
|
|
case AccessRequestEvents.Created:
|
|
await StreamAccessRequestCreatedHandler(event)
|
|
break
|
|
case AccessRequestEvents.Finalized:
|
|
await StreamAccessRequestFinalizedHandler(event)
|
|
break
|
|
default:
|
|
throw new UnhandledNotificationError(null, { info: event })
|
|
}
|
|
|
|
notificationLogger.info('Handled notifications for event')
|
|
} catch (e: unknown) {
|
|
notificationsLogger.error(e)
|
|
}
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Publish message onto the notifications queue
|
|
*/
|
|
export async function publishEventMessage(message: NotificationEvents) {
|
|
const queue = getQueue()
|
|
const job = await queue.add(message)
|
|
return job.id
|
|
}
|
|
|
|
export async function shutdownEventQueue() {
|
|
if (!queue) return
|
|
await queue.close()
|
|
}
|