@bts-soft/通知
用于NestJS应用的企业级,分布式多通道通知引擎. 构建坚持高通量,容错分布式系统架构,本套件在13个不同通信通道上管弦送,多层次供应商倒置,基于类用户偏好过滤,有时区意识的静时排程,密码化同位素分解,分布式断路器,死字排行管理,以及送货收发(DLR)处理.
建筑概况
通知子系统分为两个同步执行阶段:
- 同步摄入和飞行前验证管道: 执行请求新鲜度, 减重检查, 用户偏好过滤, 分布速率限制, 以及发布任务前的排行表延迟计算 .
- 同步工人执行和弹性调度管道: Consumes 频道分机的BullMQ队列,编译本地化模板,使用SSRF安全连接代理管理外部HTTP/SDK连接,下游出站时出站线路断路器,在瞬间故障时代表二次倒站供应商.
Client Application
|
v
+--------------------------------------------------------------------------+
| PRE-FLIGHT PIPELINE |
| |
| 1. TTL Expiration Check -> Drop if message.expiresAt has elapsed |
| 2. Idempotency Key -> Atomic Redis reservation (Deduplication Store) |
| 3. Category Filtering -> Opt-out check (TRANSACTIONAL/SECURITY bypass) |
| 4. Sliding Window Rate Limiting -> Recipient / channel burst prevention |
| 5. Quiet Hours & Scheduling -> Calculate delay from recipient timezone |
| 6. Durable State Audit -> Persist PENDING / QUEUED state in Repository |
+--------------------------------------------------------------------------+
|
v (BullMQ Channel-Partitioned Queue)
+--------------------------------------------------------------------------+
| WORKER DISPATCH PIPELINE |
| |
| 1. Worker Activation -> Update DB state to PROCESSING |
| 2. Queue Backlog Expiry Check -> Drop stale jobs if queued too long |
| 3. Template Compilation -> Handlebars string/file with i18n & helpers |
| 4. Circuit Breaker Check -> Fast-fail or redirect if provider is OPEN |
| 5. Safe Dispatch Agent -> DNS resolution validation against SSRF |
| 6. Execution -> Primary Provider (e.g. AWS SES / Twilio) |
| |--> On 4xx / Client Error: Unrecoverable fail, mark FAILED |
| |--> On 5xx / Network Error: Failover to Fallback Provider |
| 7. Observability -> Dispatch metrics, delivery logs, outbox clearance |
+--------------------------------------------------------------------------+
支持的频道提供者( S)
| 频道 | 核心供应商/一体化 | 初级能力 |
|---|---|---|
| 电子邮件 | AWS SES,Twilio SendGrid,节点邮箱(SMTP) | 多提供者故障、 HTML/文本多部分、 附件、 自定义标题. |
| 简讯 | Twilio SMS, Vonage (Nexmo), 短消息Misr | E.164 正常化、区域后退链、α发件人身份证. |
| 推开 | Firebase 云通信(FCM) | 主题广播,标语独播,Android/APNs有效载荷配置. |
| 网络推 | 原生网络推 (VAPID / RFC 8291) | 有加密有效载荷的直接浏览器推取通知. |
| 一个符号 | One Signal REST API 单声道 | 统一移动和网络推取外部用户ID目标. |
| 怎样 | Twilio 通讯 API | 沙盒和出品WhatsApp消息,媒体 URL附件. |
| 电报 | 电讯机器人 API | 直接用户消息,Markdown/HTML格式化,双向webhook链接. |
| 解析器 | Discord Webhooks API 磁盘网络游戏 | 丰富的嵌入式格式,自定义的bot avatars,用户名覆盖. |
| 偷懒 | Slack Webhooks & Web API (英语:chat.postMessage(中文(简体) ) | Block Kit 的布局, 频道选择, 符号和 Webhook 调度 . |
| 微软团队 | Office 365 / 电源自动进取 Webhooks | 适应卡和遗留的MessageCard有效载荷. |
| Facebook 通讯员 | Meta 图形发送 API | 页面缩放ID(PSID),消息标记,动作按钮. |
| 内页 | 推手频道 | 实时WebSocket向私人和在场频道广播. |
| 网页 | 通用 HTTP / HTTPS 网络呼号 | HMAC SHA-256有效载荷签名,SSF验证,可配置超时. |
安装
确保同伴的依赖性( E)@nestjs/common, (中文(简体) ), @nestjs/core, (中文(简体) ), @nestjs/bullmq, (中文(简体) ), bullmq,可选择 @bts-soft/cache) 可在您的项目工作空间中找到:
npm install @bts-soft/notifications
快速启动模块注册( M)
导入 NotificationModule 输入您的根模块。 您可以使用 : NotificationModule.register()数字 :
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { BullModule } from '@nestjs/bullmq';
import { NotificationModule, InMemoryNotificationLogRepository, NOTIFICATION_LOG_REPOSITORY } from '@bts-soft/notifications';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
BullModule.forRoot({
connection: {
host: process.env.REDIS_HOST || '127.0.0.1',
port: Number(process.env.REDIS_PORT) || 6379,
},
}),
NotificationModule.register({
providers: [
{
provide: NOTIFICATION_LOG_REPOSITORY,
useClass: InMemoryNotificationLogRepository, // Replace with your TypeORM/Prisma repository
},
],
exports: [NOTIFICATION_LOG_REPOSITORY],
}),
],
})
export class AppModule {}
配置参考
模块通过 NotificationConfigService 使用 @nestjs/config。 。 。 .
# General & Queues
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
# Email Channels
EMAIL_PROVIDER=ses # ses | sendgrid | nodemailer
EMAIL_USER=apikey
EMAIL_PASS=smtp_password
EMAIL_HOST=smtp.sendgrid.net
EMAIL_PORT=587
[email protected]
SENDGRID_API_KEY=SG.xxxxxxxx
AWS_SES_ACCESS_KEY_ID=AKIAxxxxxxxx
AWS_SES_SECRET_ACCESS_KEY=xxxxxxxx
AWS_SES_REGION=us-east-1
# SMS Channels
SMS_PROVIDER=twilio # twilio | vonage | smsmisr
TWILIO_ACCOUNT_SID=ACxxxxxxxx
TWILIO_AUTH_TOKEN=xxxxxxxx
TWILIO_SMS_NUMBER=+1234567890
VONAGE_API_KEY=xxxxxxxx
VONAGE_API_SECRET=xxxxxxxx
VONAGE_SENDER=BTSNotify
SMSMISR_USERNAME=client_user
SMSMISR_PASSWORD=client_pass
SMSMISR_SENDER=Company
SMSMISR_ENVIRONMENT=1 # 1 = Live, 2 = Test
# Push Notifications
FIREBASE_SERVICE_ACCOUNT_PATH=/secrets/firebase-service-account.json
ONESIGNAL_APP_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
ONESIGNAL_REST_API_KEY=xxxxxxxx
WEB_PUSH_PUBLIC_KEY=Bxxxxxxxx...
WEB_PUSH_PRIVATE_KEY=xxxxxxxx...
WEB_PUSH_SUBJECT=mailto:[email protected]
# Chat, Bots & Webhooks
TWILIO_WHATSAPP_NUMBER=+14155238886
TELEGRAM_BOT_TOKEN=123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
TEAMS_WEBHOOK_URL=https://outlook.office.com/webhook/...
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...
SLACK_BOT_TOKEN=xoxb-xxxxxxxx
SLACK_DEFAULT_CHANNEL=#general
FB_PAGE_ACCESS_TOKEN=EAAxxxxxxxx
FB_GRAPH_API_VERSION=v19.0
WEBHOOK_DEFAULT_SIGNING_SECRET=whsec_xxxxxxxx
# In-App Real-time
IN_APP_PROVIDER=pusher
PUSHER_APP_ID=123456
PUSHER_KEY=xxxxxxxx
PUSHER_SECRET=xxxxxxxx
PUSHER_CLUSTER=eu
核心业务特征
1. 多泰尔供应商
在发送关键信息时,对提供者进行分级评价。 如果主提供者因网络中断或下游HTTP 5xx出错而失败,该频道会自动引用倒置提供者而无需再排队或失去工作状态. 如果错误是 4xx 验证或客户端出错(如无效的收件人格式),则跳过失败,且该任务立即失败以避免重复出错.
- 电子邮件失败命令: AWS SES - > Twilio SendGrid - > 节点邮件器 (SMTP).
- 短消息失败命令: Twilio短信 - > Vonage SMS - > SMS Misr. (原始内容存档于2018-09-27).
2. 类别偏好和法律范围
每份通知都标有 NotificationCategory数字 :
TRANSACTIONAL: 关键发票、核查代码、检察官办公室、订货更新.SECURITY:密码重设请求,登录提示,双因子认证.SYSTEM:维护窗口,服务条款更新.MARKETING: 宣传活动、通讯、折扣.COMMUNITY:聊天、论坛答复、社会活动.
根据遵守框架(如GDPR和CAN-SPAM),受援国可选择退出 MARKETING, (中文(简体) ), SYSTEM,或 COMMUNITY 类别。 相比之下, TRANSACTIONAL 财务报告和审定财务报表 SECURITY 消息由架构执行,不能被用户选择退出的旗帜所压制.
await notificationService.send(ChannelType.EMAIL, {
recipientId: '[email protected]',
category: NotificationCategory.TRANSACTIONAL, // Bypasses opt-out checks
subject: 'Order Confirmation',
body: 'Your order #10892 has been confirmed.',
});
3. 安静小时和时间安排
标记为非紧急的通知可在接收者的优惠记录中定义的安静时间中保存:
- 考虑到受援方的本地
timezone(例如:.Africa/Cairo, (中文(简体) ),America/New_York) (中文(简体) ). - 评价始末窗口(例如,
22:00改为08:00) (中文(简体) ). - 使用 BullMQ 工作延迟计算确切的延迟, 并推迟队列处理 .
- 关键类别
TRANSACTIONAL, (中文(简体) ),SECURITY或与priority: NotificationPriority.HIGH自动绕过安静时间.
4. 同上, " 完全 " 交货
利用原子分布分解来防止由网络重试或分布种族引起的重复发送尝试.
当 idempotencyKey 规定如下:
- 商店进行解剖检查,并用可配置的TTL来设置Redis中的密钥.
- 收件人识别符在存储前被散列,以维护隐私.
- 如果显示重复的密钥,则任务标记为
SKIPPED有理无据DUPLICATE,而现有的工作ID不重复发送.
5. SSRF 国防和安全HTTP调度
对于与外部 URL 互动的频道( 如 Webhooks 和 Discord) :
SafeAgentFactory在打开 TCP 套接字前的 DNS 解析阶段验证 IP 地址 .- 私人网络范围(RFC 1918),回回接口(C
127.0.0.0/8, (中文(简体) ),::1页:1169.254.169.254),并拒绝载体级NAT区块. - 防止时间检查到时间使用(TOCTOU) DNS重新绑定攻击.
6. 交易收发箱中继器
对于必须在通知中排队参与数据库交易的特派团关键行动:
- 使用您
INotificationOutboxRepository。 。 。 . NotificationOutboxRelay.drainOnce()提出未处理的、具有租赁期的批次.- 成功发送的信件被标记为被排列; 失败的发送被安排为指数重试或被路由到死信存储 .
// Inside your scheduled cron job or worker service
@Injectable()
export class NotificationCronService {
constructor(private readonly outboxRelay: NotificationOutboxRelay) {}
@Cron('*/10 * * * * *')
async handleOutboxSweep() {
await this.outboxRelay.drainOnce({
batchSize: 100,
leaseMs: 30000,
retryBaseDelayMs: 5000,
retryMaxDelayMs: 300000,
});
}
}
7. 交货收据(DLR)处理
软件包包括 NotificationDeliveryReceiptService 处理来自下游通信提供者的同步网络hooks(例如Twilio SMS发送报告或SendGrid回放网络hooks).
@Controller('webhooks/notifications')
export class NotificationCallbackController {
constructor(private readonly dlrService: NotificationDeliveryReceiptService) {}
@Post('twilio')
async handleTwilioDlr(@Body() body: any) {
await this.dlrService.processReceipt({
provider: 'twilio',
providerMessageId: body.MessageSid,
status: body.MessageStatus === 'delivered' ? 'delivered' : 'failed',
reason: body.ErrorMessage,
timestamp: new Date(),
});
return { received: true };
}
}
详细频道文档
对于特定提供者的设置指南,配置矩阵和频道选项,请参考每个频道目录中的文档:
- 电子邮件频道文档
- 短消息频道文档
- WhatsApp 频道文档
- Telegram Bot 频道文档
- Firebase 云传通道文档
- 本地 Web Push 频道文档
- One Signal 频道文档
- Discord 频道文档
- 黑频道文档
- 微软团队频道文档
- Facebook 信使频道文档
- App Pusher 频道文档
- 通用 Webhook 频道文档
测试
该套件包括单元测试套件和综合端到端整合测试:
# Execute unit test suites
npm run test
# Execute test suite with V8 code coverage report
npm run test:cov
# Execute automated Docker-composed End-to-End integration suite
npm run test:e2e
# Execute E2E integration against a locally running Redis instance
npm run test:e2e:local
许可证
这个包裹根据麻省理工学院的许可证获得许可.