Skip to content
/ core Public

Commit 26896fe

Browse files
committed
feat(event): add AGGREGATE_UPDATE event and enhance config update notifications
- Introduced AGGREGATE_UPDATE event to BusinessEvents for better event handling. - Updated ConfigsService, OwnerService, and SnippetService to emit AGGREGATE_UPDATE on relevant updates. - Added AggregateUpdatePayload interface to define the structure of the aggregate update event payload. - Refactored cache cleaning logic to improve maintainability and clarity. Signed-off-by: Innei <[email protected]>
1 parent 1d7e836 commit 26896fe

File tree

6 files changed

+106
-18
lines changed

6 files changed

+106
-18
lines changed

apps/core/src/constants/business-event.constant.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ export enum BusinessEvents {
4444
RECENTLY_UPDATE = 'RECENTLY_UPDATE',
4545
RECENTLY_DELETE = 'RECENTLY_DELETE',
4646

47+
AGGREGATE_UPDATE = 'AGGREGATE_UPDATE',
48+
4749
// AI Translation
4850
TRANSLATION_CREATE = 'TRANSLATION_CREATE',
4951
TRANSLATION_UPDATE = 'TRANSLATION_UPDATE',

apps/core/src/modules/configs/configs.service.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { cloneDeep, merge, mergeWith } from 'es-toolkit/compat'
55
import type { z, ZodError } from 'zod'
66

77
import { BizException } from '~/common/exceptions/biz.exception'
8-
import { EventScope } from '~/constants/business-event.constant'
8+
import { BusinessEvents, EventScope } from '~/constants/business-event.constant'
99
import { RedisKeys } from '~/constants/cache.constant'
1010
import { ErrorCodeEnum } from '~/constants/error-code.constant'
1111
import { EventBusEvents } from '~/constants/event-bus.constant'
@@ -32,6 +32,12 @@ import { OptionModel } from './configs.model'
3232
import type { OAuthConfig } from './configs.schema'
3333

3434
const configsKeySet = new Set(Object.keys(configDtoMapping))
35+
const aggregateConfigKeys = new Set<keyof IConfig>([
36+
'ai',
37+
'commentOptions',
38+
'seo',
39+
'url',
40+
])
3541

3642
/*
3743
* NOTE:
@@ -220,6 +226,28 @@ export class ConfigsService implements OnModuleInit {
220226
return newData
221227
}
222228

229+
private async notifyAggregateConfigUpdate<T extends keyof IConfig>(key: T) {
230+
if (!aggregateConfigKeys.has(key)) {
231+
return
232+
}
233+
234+
await Promise.all([
235+
this.eventManager.emit(EventBusEvents.CleanAggregateCache, null, {
236+
scope: EventScope.TO_SYSTEM,
237+
}),
238+
this.eventManager.emit(
239+
BusinessEvents.AGGREGATE_UPDATE,
240+
{
241+
source: 'config',
242+
keys: [key],
243+
},
244+
{
245+
scope: EventScope.TO_SYSTEM,
246+
},
247+
),
248+
])
249+
}
250+
223251
async patchAndValid<T extends keyof IConfig>(
224252
key: T,
225253
value: Partial<IConfig[T]>,
@@ -261,6 +289,7 @@ export class ConfigsService implements OnModuleInit {
261289
case 'url': {
262290
const newValue = await this.patch(key, instanceValue as any)
263291
await this.configVersionService.bump(ConfigVersionScopes.Url)
292+
await this.notifyAggregateConfigUpdate(key)
264293
return newValue
265294
}
266295
case 'mailOptions': {
@@ -316,7 +345,9 @@ export class ConfigsService implements OnModuleInit {
316345
}
317346

318347
default: {
319-
return this.patch(key, instanceValue as any)
348+
const nextValue = await this.patch(key, instanceValue as any)
349+
await this.notifyAggregateConfigUpdate(key)
350+
return nextValue
320351
}
321352
}
322353
}

apps/core/src/modules/owner/owner.service.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
import { Injectable, Logger } from '@nestjs/common'
22
import type { ReturnModelType } from '@typegoose/typegoose'
3+
import { Types } from 'mongoose'
4+
35
import { BizException } from '~/common/exceptions/biz.exception'
6+
import { BusinessEvents, EventScope } from '~/constants/business-event.constant'
47
import {
58
OWNER_PROFILE_COLLECTION_NAME,
69
READER_COLLECTION_NAME,
710
} from '~/constants/db.constant'
811
import { ErrorCodeEnum } from '~/constants/error-code.constant'
12+
import { EventBusEvents } from '~/constants/event-bus.constant'
913
import { DatabaseService } from '~/processors/database/database.service'
14+
import { EventManagerService } from '~/processors/helper/helper.event.service'
1015
import { InjectModel } from '~/transformers/model.transformer'
1116
import { getAvatar } from '~/utils/tool.util'
12-
import { Types } from 'mongoose'
13-
import { OwnerProfileModel } from './owner-profile.model'
17+
1418
import type { OwnerDocument } from './owner.model'
1519
import { OwnerModel } from './owner.model'
20+
import { OwnerProfileModel } from './owner-profile.model'
1621

1722
@Injectable()
1823
export class OwnerService {
@@ -24,6 +29,7 @@ export class OwnerService {
2429
private readonly ownerProfileModel: ReturnModelType<
2530
typeof OwnerProfileModel
2631
>,
32+
private readonly eventManager: EventManagerService,
2733
) {}
2834

2935
private get readersCollection() {
@@ -130,7 +136,8 @@ export class OwnerService {
130136
readerPatch.image = data.avatar
131137
}
132138

133-
if (Object.keys(readerPatch).length > 0) {
139+
const hasReaderPatch = Object.keys(readerPatch).length > 0
140+
if (hasReaderPatch) {
134141
readerPatch.updatedAt = new Date()
135142
await this.readersCollection.updateOne(
136143
{ _id: reader._id },
@@ -152,7 +159,8 @@ export class OwnerService {
152159
profilePatch.socialIds = data.socialIds
153160
}
154161

155-
if (Object.keys(profilePatch).length > 0) {
162+
const hasProfilePatch = Object.keys(profilePatch).length > 0
163+
if (hasProfilePatch) {
156164
await this.ownerProfileModel.updateOne(
157165
{ readerId: reader._id },
158166
{
@@ -166,6 +174,24 @@ export class OwnerService {
166174
)
167175
}
168176

177+
if (hasReaderPatch || hasProfilePatch) {
178+
await Promise.all([
179+
this.eventManager.emit(EventBusEvents.CleanAggregateCache, null, {
180+
scope: EventScope.TO_SYSTEM,
181+
}),
182+
this.eventManager.emit(
183+
BusinessEvents.AGGREGATE_UPDATE,
184+
{
185+
source: 'owner',
186+
keys: ['user'],
187+
},
188+
{
189+
scope: EventScope.TO_SYSTEM,
190+
},
191+
),
192+
])
193+
}
194+
169195
return this.getOwnerInfo(true)
170196
}
171197

apps/core/src/modules/snippet/snippet.service.ts

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { forwardRef, Inject, Injectable } from '@nestjs/common'
2+
import { load } from 'js-yaml'
3+
import JSON5 from 'json5'
4+
import type { AggregatePaginateModel, Document } from 'mongoose'
5+
import qs from 'qs'
6+
27
import { RequestContext } from '~/common/contexts/request.context'
38
import { BizException } from '~/common/exceptions/biz.exception'
4-
import { EventScope } from '~/constants/business-event.constant'
9+
import { BusinessEvents, EventScope } from '~/constants/business-event.constant'
510
import { RedisKeys } from '~/constants/cache.constant'
611
import { ErrorCodeEnum } from '~/constants/error-code.constant'
712
import { EventBusEvents } from '~/constants/event-bus.constant'
@@ -10,10 +15,7 @@ import { RedisService } from '~/processors/redis/redis.service'
1015
import { InjectModel } from '~/transformers/model.transformer'
1116
import { EncryptUtil } from '~/utils/encrypt.util'
1217
import { getRedisKey } from '~/utils/redis.util'
13-
import { load } from 'js-yaml'
14-
import JSON5 from 'json5'
15-
import type { AggregatePaginateModel, Document } from 'mongoose'
16-
import qs from 'qs'
18+
1719
import { ServerlessService } from '../serverless/serverless.service'
1820
import { SnippetModel, SnippetType } from './snippet.model'
1921

@@ -35,6 +37,24 @@ export class SnippetService {
3537

3638
private readonly reservedReferenceKeys = ['system', 'built-in']
3739

40+
private async notifyAggregateThemeUpdate() {
41+
await Promise.all([
42+
this.eventManager.emit(EventBusEvents.CleanAggregateCache, null, {
43+
scope: EventScope.TO_SYSTEM,
44+
}),
45+
this.eventManager.emit(
46+
BusinessEvents.AGGREGATE_UPDATE,
47+
{
48+
source: 'theme',
49+
keys: ['theme'],
50+
},
51+
{
52+
scope: EventScope.TO_SYSTEM,
53+
},
54+
),
55+
])
56+
}
57+
3858
async create(model: SnippetModel) {
3959
if (model.type === SnippetType.Function) {
4060
model.method ??= 'GET'
@@ -80,13 +100,12 @@ export class SnippetService {
80100
}
81101
}
82102

103+
const created = await this.model.create({ ...model, created: new Date() })
83104
if (model.reference === 'theme') {
84-
await this.eventManager.emit(EventBusEvents.CleanAggregateCache, null, {
85-
scope: EventScope.TO_SYSTEM,
86-
})
105+
await this.notifyAggregateThemeUpdate()
87106
}
88107

89-
return await this.model.create({ ...model, created: new Date() })
108+
return created
90109
}
91110

92111
async update(id: string, newModel: SnippetModel) {
@@ -179,9 +198,7 @@ export class SnippetService {
179198
})
180199

181200
if (old.reference === 'theme' || newModel.reference === 'theme') {
182-
await this.eventManager.emit(EventBusEvents.CleanAggregateCache, null, {
183-
scope: EventScope.TO_SYSTEM,
184-
})
201+
await this.notifyAggregateThemeUpdate()
185202
}
186203

187204
if (!newerDoc) {
@@ -208,6 +225,9 @@ export class SnippetService {
208225
if (doc.customPath) {
209226
await this.deleteCachedSnippetByCustomPath(doc.customPath)
210227
}
228+
if (doc.reference === 'theme') {
229+
await this.notifyAggregateThemeUpdate()
230+
}
211231
}
212232

213233
private async validateTypeAndCleanup(model: SnippetModel) {

packages/webhook/src/models.generated.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export enum BusinessEvents {
3232
RECENTLY_CREATE = 'RECENTLY_CREATE',
3333
RECENTLY_UPDATE = 'RECENTLY_UPDATE',
3434
RECENTLY_DELETE = 'RECENTLY_DELETE',
35+
AGGREGATE_UPDATE = 'AGGREGATE_UPDATE',
3536
TRANSLATION_CREATE = 'TRANSLATION_CREATE',
3637
TRANSLATION_UPDATE = 'TRANSLATION_UPDATE',
3738
CONTENT_REFRESH = 'CONTENT_REFRESH',
@@ -163,6 +164,7 @@ export interface CommentModel extends BaseModel {
163164
location?: string
164165
isWhispers?: boolean
165166
avatar?: string
167+
authProvider?: string
166168
meta?: string
167169
readerId?: string
168170
editedAt?: Date

packages/webhook/src/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ export interface ExtendedEventEmitter extends EventEmitter {
2828
}
2929
export type Id = string
3030
export type PayloadOnlyId = { data: Id }
31+
export interface AggregateUpdatePayload {
32+
source: 'config' | 'owner' | 'theme'
33+
keys: string[]
34+
}
3135
export interface EventPayloadMapping {
3236
[BusinessEvents.POST_CREATE]: NormalizedPost
3337
[BusinessEvents.POST_UPDATE]: NormalizedPost
@@ -48,6 +52,8 @@ export interface EventPayloadMapping {
4852
[BusinessEvents.RECENTLY_CREATE]: RecentlyModel
4953
[BusinessEvents.RECENTLY_UPDATE]: RecentlyModel
5054

55+
[BusinessEvents.AGGREGATE_UPDATE]: AggregateUpdatePayload
56+
5157
[BusinessEvents.ACTIVITY_LIKE]: IActivityLike
5258

5359
[BusinessEvents.LINK_APPLY]: LinkModel
@@ -97,6 +103,7 @@ export type GenericEvent =
97103
| { type: BusinessEvents.SAY_DELETE; payload: PayloadOnlyId }
98104
| { type: BusinessEvents.RECENTLY_CREATE; payload: RecentlyModel }
99105
| { type: BusinessEvents.RECENTLY_UPDATE; payload: RecentlyModel }
106+
| { type: BusinessEvents.AGGREGATE_UPDATE; payload: AggregateUpdatePayload }
100107
| { type: BusinessEvents.ACTIVITY_LIKE; payload: IActivityLike }
101108
| { type: BusinessEvents.LINK_APPLY; payload: LinkModel }
102109
| {

0 commit comments

Comments
 (0)