@d1-always/event-manager
v1.0.1
Published
一个高性能、类型安全的事件管理器,专为可靠的事件数据上报而设计。支持队列管理、智能重试、持久化存储等企业级特性。
Readme
@d1-always/event-manager
一个高性能、类型安全的事件管理器,专为可靠的事件数据上报而设计。支持队列管理、智能重试、持久化存储等企业级特性。
✨ 特性
- 🚀 高性能批处理 - 智能队列管理,支持批量事件处理
- 🔄 智能重试机制 - 可配置的自动重试,确保数据不丢失
- 💾 持久化存储 - 支持 localStorage、sessionStorage 或自定义存储
- 🛡️ 完整类型安全 - 基于 TypeScript,提供完整的类型定义
- 🎯 参数验证 - 内置必要参数检查,确保数据完整性
- 🔧 高度可配置 - 灵活的配置选项满足各种业务场景
- 🌐 国际化支持 - 可自定义错误消息和提示文本
- 📊 监控友好 - 丰富的事件钩子和统计信息
- ♻️ 生命周期管理 - 完整的启动/暂停/停止/销毁控制
📦 安装
npm install @d1-always/event-manageryarn add @d1-always/event-managerpnpm add @d1-always/event-manager🚀 快速开始
基础示例
import { EventManager } from '@d1-always/event-manager';
// 定义事件数据类型
interface UserEvent {
action: string;
userId: string;
page?: string;
}
// 定义上报数据类型
interface ReportData {
event_type: string;
user_id: string;
timestamp: number;
properties: Record<string, any>;
}
// 实现事件管理器
class MyEventManager extends EventManager<UserEvent, ReportData> {
constructor() {
super({
storage: localStorage,
key: 'user_events',
max_event_num: 10,
delay_time: 3,
debug: true
});
// 设置事件钩子
this.setEventHooks({
onSuccess: (count) => console.log(`✅ 成功上报 ${count} 个事件`),
onError: (error) => console.error('❌ 上报失败:', error)
});
}
// 构造上报数据
buildEvent(timestamp: number, eventInfo: UserEvent): ReportData {
return {
event_type: eventInfo.action,
user_id: eventInfo.userId,
timestamp,
properties: {
page: eventInfo.page || window.location.pathname,
user_agent: navigator.userAgent
}
};
}
// 实现上报逻辑
async reportEvent(eventList: EventManager.ReportEvent<ReportData>[]) {
try {
const response = await fetch('/api/events', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(eventList.map(e => e.eventInfo))
});
if (response.ok) {
return eventList; // 返回成功的事件
}
throw new Error(`HTTP ${response.status}`);
} catch (error) {
console.error('上报请求失败:', error);
return []; // 返回空数组表示全部失败
}
}
}
// 创建实例并使用
const eventManager = new MyEventManager();
// 推送事件
eventManager.pushEvent({
required_keys: ['userId'], // 必要字段检查
timestamp: Date.now(),
retry_times: 0,
eventInfo: {
action: 'page_view',
userId: '12345',
page: '/dashboard'
}
});📚 API 文档
构造函数选项
interface Options {
max_event_num: number; // 每批最大事件数,默认 10
max_retry_times: number; // 最大重试次数,默认 3
max_queue_len: number; // 队列最大长度,默认 1000
max_empty_run_times: number; // 空队列休眠阈值,默认 10
delay_time: number; // 处理间隔(秒),默认 3
debug?: boolean; // 调试模式,默认 false
logLevel?: LogLevel; // 日志级别,默认 'warn'
autoStart?: boolean; // 自动开始,默认 true
storage?: StorageLike; // 存储对象(可选)
key?: string; // 存储键名(使用存储时必需)
}核心方法
事件操作
// 推送单个事件
pushEvent(event: EventInfo<T>): boolean
// 批量推送事件
pushEvents(events: EventInfo<T>[]): number
// 清空队列
clear(): void生命周期控制
start(): Promise<void> // 开始处理
pause(): void // 暂停处理
resume(): void // 恢复处理
stop(): void // 停止处理(可恢复)
destroy(): void // 销毁实例(不可恢复)配置管理
// 更新配置
updateOptions(options: Partial<Options>): void
// 获取当前配置
getOptions(): Readonly<Options>
// 设置事件钩子
setEventHooks(hooks: Partial<EventHooks<T>>): void
// 设置消息文本(国际化)
setMessages(messages: Partial<Messages>): void状态监控
// 获取运行状态
getStats(): Stats
interface Stats {
queueLength: number; // 队列长度
emptyRunTimes: number; // 空运行次数
isRunning: boolean; // 是否运行中
isPaused: boolean; // 是否已暂停
isDestroyed: boolean; // 是否已销毁
}抽象方法(需实现)
// 构造上报数据
abstract buildEvent(timestamp: number, eventInfo: T): R;
// 执行事件上报
abstract reportEvent(events: ReportEvent<R>[]): Promise<ReportEvent<R>[]>;事件钩子
interface EventHooks<T> {
onSuccess?: (count: number) => void; // 上报成功
onError?: (error: string, events: EventInfo<T>[]) => void; // 发生错误
onMaxRetryReached?: (events: EventInfo<T>[]) => void; // 达到最大重试次数
onQueueFull?: (event: EventInfo<T>) => void; // 队列已满
}📖 使用场景
1. 用户行为追踪
interface UserAction {
event: string;
userId: string;
elementId?: string;
}
class BehaviorTracker extends EventManager<UserAction, any> {
constructor() {
super({
storage: localStorage,
key: 'behavior_events',
max_event_num: 20,
delay_time: 1
});
}
buildEvent(timestamp: number, { event, userId, elementId }: UserAction) {
return {
event_name: event,
user_id: userId,
element_id: elementId,
timestamp,
page_url: location.href
};
}
async reportEvent(events: EventManager.ReportEvent<any>[]) {
const response = await fetch('/api/analytics', {
method: 'POST',
body: JSON.stringify(events.map(e => e.eventInfo))
});
return response.ok ? events : [];
}
// 便捷方法
trackClick(elementId: string, userId: string) {
this.pushEvent({
required_keys: ['userId'],
timestamp: Date.now(),
retry_times: 0,
eventInfo: { event: 'click', userId, elementId }
});
}
}
const tracker = new BehaviorTracker();
tracker.trackClick('submit-btn', 'user123');2. 错误日志上报
interface ErrorEvent {
error: Error;
userId?: string;
context?: Record<string, any>;
}
class ErrorReporter extends EventManager<ErrorEvent, any> {
constructor() {
super({
max_retry_times: 5, // 错误日志重试更多次
max_event_num: 5,
delay_time: 0.5, // 更快上报
logLevel: 'error'
});
}
buildEvent(timestamp: number, { error, userId, context }: ErrorEvent) {
return {
level: 'error',
message: error.message,
stack: error.stack,
user_id: userId,
url: location.href,
timestamp,
context
};
}
async reportEvent(events: EventManager.ReportEvent<any>[]) {
const response = await fetch('/api/errors', {
method: 'POST',
body: JSON.stringify(events.map(e => e.eventInfo))
});
return response.ok ? events : [];
}
logError(error: Error, userId?: string, context?: Record<string, any>) {
this.pushEvent({
required_keys: [],
timestamp: Date.now(),
retry_times: 0,
eventInfo: { error, userId, context }
});
}
}
// 全局错误监听
const errorReporter = new ErrorReporter();
window.addEventListener('error', (e) => {
errorReporter.logError(new Error(e.message));
});3. 业务指标收集
interface Metric {
name: string;
value: number;
tags?: Record<string, string>;
}
class MetricsCollector extends EventManager<Metric, any> {
constructor() {
super({
max_event_num: 50,
delay_time: 10, // 10秒批量上报
storage: localStorage,
key: 'metrics'
});
}
buildEvent(timestamp: number, { name, value, tags }: Metric) {
return {
metric_name: name,
value,
timestamp,
tags: { ...tags, host: location.hostname }
};
}
async reportEvent(events: EventManager.ReportEvent<any>[]) {
const response = await fetch('/api/metrics', {
method: 'POST',
body: JSON.stringify(events.map(e => e.eventInfo))
});
return response.ok ? events : [];
}
recordTiming(operation: string, duration: number) {
this.pushEvent({
required_keys: [],
timestamp: Date.now(),
retry_times: 0,
eventInfo: {
name: 'operation_duration',
value: duration,
tags: { operation }
}
});
}
}
const metrics = new MetricsCollector();
const start = performance.now();
// ... 执行操作
metrics.recordTiming('api_call', performance.now() - start);🔧 高级配置
自定义存储
class CustomStorage implements EventManager.StorageLike {
private cache = new Map<string, string>();
get(key: string): string | null {
return this.cache.get(key) || null;
}
set(key: string, value: string): void {
this.cache.set(key, value);
// 可添加持久化逻辑
this.saveToDatabase(key, value);
}
private async saveToDatabase(key: string, value: string) {
// 自定义持久化逻辑
}
}多环境配置
const isDev = process.env.NODE_ENV === 'development';
const eventManager = new MyEventManager({
debug: isDev,
logLevel: isDev ? 'debug' : 'warn',
delay_time: isDev ? 1 : 5,
max_event_num: isDev ? 3 : 20
});条件上报
class ConditionalEventManager extends EventManager<any, any> {
private enabled = true;
async reportEvent(events: EventManager.ReportEvent<any>[]) {
if (!this.enabled) return [];
// 根据其他条件决定是否上报
const shouldReport = await this.checkReportingConditions();
if (!shouldReport) return [];
// 执行实际上报
return this.performReport(events);
}
setEnabled(enabled: boolean) {
this.enabled = enabled;
if (!enabled) this.pause();
else this.resume();
}
private async checkReportingConditions(): Promise<boolean> {
// 自定义条件判断逻辑
return true;
}
}📋 最佳实践
合理设置队列大小
// 根据业务量调整,避免内存溢出 max_queue_len: 1000优化上报频率
// 平衡及时性和性能 delay_time: 3, // 3秒间隔 max_event_num: 10 // 每批10个事件错误处理
this.setEventHooks({ onError: (error, events) => { // 记录错误日志 console.error('Event error:', error); // 可选:发送到监控系统 sendToMonitoring(error, events); } });资源清理
// 组件销毁时清理资源 componentWillUnmount() { this.eventManager.destroy(); }开发调试
if (process.env.NODE_ENV === 'development') { eventManager.updateOptions({ debug: true, logLevel: 'debug' }); }
🔄 CI/CD 流程
自动化工作流
项目采用 GitHub Actions 实现全自动 CI/CD 流程:
🔍 PR 检查流程
- 触发条件: PR 创建/更新
- 检查项目:
- TypeScript 类型检查
- 项目构建测试
- 包结构验证
- 自动化测试
🚀 自动发布流程
- 触发条件: 合并到 main 分支
- 发布条件: package.json 版本号变更
- 自动执行:
- 检查版本是否已发布
- 构建和测试
- 发布到 NPM
- 创建 GitHub Release
- 发送通知
📦 发布新版本
更新版本号
# 手动更新 package.json 中的 version vim package.json提交到 main 分支
git add package.json git commit -m "chore: bump version to x.x.x" git push origin main自动发布
- GitHub Actions 会自动检测版本变更
- 执行构建、测试和发布流程
- 发布成功后创建 GitHub Release
🔧 配置要求
为了让 CI/CD 正常工作,需要在 GitHub 仓库中配置:
- NPM_TOKEN: NPM 发布令牌(Repository Secrets)
- GITHUB_TOKEN: GitHub API 令牌(自动提供)
🤝 贡献
我们欢迎任何形式的贡献!请查看 贡献指南 了解详细信息。
快速贡献流程
- Fork 项目仓库
- 创建功能分支:
git checkout -b feature/amazing-feature - 提交更改:
git commit -m 'feat: add amazing feature' - 推送分支:
git push origin feature/amazing-feature - 创建 Pull Request
📄 许可证
需要帮助? 请查看 Issues 或提交新的问题。
