@klsakura/rocketmq-native-sdk
Version:
High-performance Node.js client SDK for RocketMQ with Native Addon support (Node.js 16+)
407 lines (344 loc) • 14 kB
text/typescript
import * as path from 'path';
// 动态导入平台加载器(支持ESM和CommonJS)
let loadNativeAddon: () => any;
try {
// 尝试使用require (CommonJS)
loadNativeAddon = require('./platform-loader').loadNativeAddon;
} catch (e) {
// 如果require失败,将在运行时使用动态import (ESM)
loadNativeAddon = null as any;
}
// 接口定义
export interface MQConfig {
endpoint: string;
accessKeyId: string;
accessKeySecret: string;
instanceId: string;
logLevel?: string; // 可选:日志级别 (debug, info, warn, error, fatal)
thread?: number; // 可选:消费者并发线程数,默认为 20
}
export interface MessageData {
messageId: string;
receiptHandle: string;
body: string;
tag: string;
properties: { [key: string]: string };
bornTimestamp: number;
reconsumeTimes: number;
}
export interface SendResult {
messageId: string;
receiptHandle: string;
}
export interface DelayOptions {
delayTimeLevel?: number;
startDeliverTime?: number;
}
// MessageProperties类
export class MessageProperties {
public properties: { [key: string]: string } = {};
public message_key: string = '';
public sharding_key: string = '';
public start_deliver_time: number = 0;
public trans_check_immunity_time: number = 0;
putProperty(key: string, value: string | number): MessageProperties {
this.properties[key] = String(value);
return this;
}
messageKey(key: string): MessageProperties {
this.message_key = String(key);
return this;
}
shardingKey(key: string): MessageProperties {
this.sharding_key = String(key);
return this;
}
startDeliverTime(time: number): MessageProperties {
this.start_deliver_time = Number(time);
// 同时设置RocketMQ标准属性
this.properties['__STARTDELIVERTIME'] = String(time);
return this;
}
transCheckImmunityTime(time: number): MessageProperties {
this.trans_check_immunity_time = Number(time);
return this;
}
toJSON(): any {
const result: any = {
properties: this.properties,
messageKey: this.message_key,
shardingKey: this.sharding_key,
transCheckImmunityTime: this.trans_check_immunity_time
};
// 只有在没有设置 __STARTDELIVERTIME 属性时才包含 startDeliverTime
if (!this.properties['__STARTDELIVERTIME'] && this.start_deliver_time > 0) {
result.startDeliverTime = this.start_deliver_time;
}
return result;
}
}
// Native客户端实现
class NativeClient {
private nativeClient: any;
private config: MQConfig;
constructor(config: MQConfig) {
this.config = config;
}
public async initNativeClient() {
try {
// 如果是ESM环境,使用动态导入
if (!loadNativeAddon) {
// @ts-ignore - 动态导入平台加载器
const module = await import('./platform-loader.js');
loadNativeAddon = module.loadNativeAddon;
}
// 使用平台加载器加载Native Addon
const addon = loadNativeAddon();
this.nativeClient = new addon.RocketMQClient();
// 初始化RocketMQ
const configJson = {
endpoint: this.config.endpoint,
accessKeyId: this.config.accessKeyId,
accessKeySecret: this.config.accessKeySecret,
instanceId: this.config.instanceId,
...(this.config.logLevel && { logLevel: this.config.logLevel }),
...(this.config.thread && { thread: this.config.thread })
};
const result = this.nativeClient.initRocketMQ(configJson);
if (!result.success) {
throw new Error(`Failed to initialize RocketMQ: ${result.message}`);
}
console.log('🚀 RocketMQ Native Client initialized successfully');
} catch (error: any) {
throw new Error(`Failed to load Native Addon: ${error.message}`);
}
}
async getProducer(instanceId: string, topic: string): Promise<Producer> {
const configJson = JSON.stringify(this.config);
const producer = this.nativeClient.createProducer(configJson, topic);
if (producer.success === false) {
throw new Error(`Failed to create producer: ${producer.message}`);
}
return new NativeProducer(producer, this.nativeClient);
}
async getConsumer(instanceId: string, topic: string, groupId: string, tagExpression: string = '*'): Promise<Consumer> {
const configJson = JSON.stringify(this.config);
const consumer = this.nativeClient.createConsumer(configJson, topic, groupId, tagExpression);
if (consumer.success === false) {
throw new Error(`Failed to create consumer: ${consumer.message}`);
}
return new NativeConsumer(consumer, this.nativeClient);
}
async healthCheck(): Promise<any> {
return {
status: 'healthy',
mode: 'native',
timestamp: Date.now()
};
}
}
// 生产者抽象类
export abstract class Producer {
abstract publishMessage(messageBody: any, tag?: string, properties?: MessageProperties | null): Promise<SendResult>;
abstract publishOrderedMessage(messageBody: any, tag?: string, properties?: MessageProperties | null, shardingKey?: string): Promise<SendResult>;
abstract publishDelayMessage(messageBody: any, tag?: string, properties?: MessageProperties | null, options?: DelayOptions): Promise<SendResult>;
abstract shutdown(): Promise<any>;
}
// Native生产者实现
class NativeProducer extends Producer {
constructor(private producerInfo: any, private nativeClient: any) {
super();
}
async publishMessage(messageBody: any, tag: string = '', properties: MessageProperties | null = null): Promise<SendResult> {
const body = typeof messageBody === 'object' ? JSON.stringify(messageBody) : String(messageBody);
const props = properties ? JSON.stringify(properties.toJSON()) : '{}';
const result = this.nativeClient.sendMessage(this.producerInfo.producerId, body, tag, props);
if (!result || typeof result === 'string') {
// 如果返回字符串,假设是成功的消息ID
return {
messageId: result || 'unknown',
receiptHandle: result || 'unknown'
};
}
if (!result.success) {
throw new Error(`Failed to send message: ${result.message}`);
}
return {
messageId: result.messageId,
receiptHandle: result.receiptHandle
};
}
async publishOrderedMessage(messageBody: any, tag: string = '', properties: MessageProperties | null = null, shardingKey?: string): Promise<SendResult> {
const body = typeof messageBody === 'object' ? JSON.stringify(messageBody) : String(messageBody);
const props = properties ? JSON.stringify(properties.toJSON()) : '{}';
const result = this.nativeClient.sendOrderedMessage(this.producerInfo.producerId, body, tag, props, shardingKey || '');
if (!result || typeof result === 'string') {
// 如果返回字符串,假设是成功的消息ID
return {
messageId: result || 'unknown',
receiptHandle: result || 'unknown'
};
}
if (!result.success) {
throw new Error(`Failed to send ordered message: ${result.message}`);
}
return {
messageId: result.messageId,
receiptHandle: result.receiptHandle
};
}
async publishDelayMessage(messageBody: any, tag: string = '', properties: MessageProperties | null = null, options: DelayOptions = {}): Promise<SendResult> {
// 对于延迟消息,将延迟时间设置到properties中
const props: any = properties ? properties.toJSON() : {};
// RocketMQ任意精度延迟消息:使用 __STARTDELIVERTIME 属性
if (options.startDeliverTime) {
props.properties = props.properties || {};
props.properties['__STARTDELIVERTIME'] = String(options.startDeliverTime);
}
// RocketMQ传统延迟等级:使用 delayTimeLevel
if (options.delayTimeLevel) {
props.delayTimeLevel = options.delayTimeLevel;
}
const body = typeof messageBody === 'object' ? JSON.stringify(messageBody) : String(messageBody);
const result = this.nativeClient.sendMessage(this.producerInfo.producerId, body, tag, JSON.stringify(props));
if (!result || typeof result === 'string') {
// 如果返回字符串,假设是成功的消息ID
return {
messageId: result || 'unknown',
receiptHandle: result || 'unknown'
};
}
if (!result.success) {
throw new Error(`Failed to send delay message: ${result.message}`);
}
return {
messageId: result.messageId,
receiptHandle: result.receiptHandle
};
}
async shutdown(): Promise<any> {
const result = this.nativeClient.shutdownProducer(this.producerInfo.producerId);
if (!result || typeof result === 'string') {
return { success: true, message: 'Producer shutdown' };
}
if (!result.success) {
throw new Error(`Failed to shutdown producer: ${result.message}`);
}
return result;
}
}
// 消费者抽象类
export abstract class Consumer {
protected messageHandlers: Array<(message: MessageData) => void | Promise<void>> = [];
abstract onMessage(handler: (message: MessageData) => void | Promise<void>): void;
abstract startReceiving(tagExpression?: string): any;
abstract ackMessage(receiptHandle: string): Promise<any>;
abstract shutdown(): Promise<any>;
}
// Native消费者实现
class NativeConsumer extends Consumer {
constructor(private consumerInfo: any, private nativeClient: any) {
super();
}
onMessage(handler: (message: MessageData) => void | Promise<void>): void {
this.messageHandlers.push(handler);
// 注册消息处理器到Native Addon
this.nativeClient.registerMessageHandler(this.consumerInfo.consumerId, (messageJson: string) => {
try {
// 解析消息JSON
const messageData = JSON.parse(messageJson);
// 调用所有注册的处理器
for (const h of this.messageHandlers) {
try {
h(messageData);
} catch (error) {
console.error('Error in message handler:', error);
}
}
} catch (error) {
console.error('Error parsing message JSON:', error);
}
});
}
startReceiving(tagExpression: string = '*'): any {
const result = this.nativeClient.startConsumer(this.consumerInfo.consumerId, this.consumerInfo.topic || '', tagExpression);
if (!result || typeof result === 'string') {
return { success: true, message: 'Consumer started' };
}
if (!result.success) {
throw new Error(`Failed to start receiving: ${result.message}`);
}
return result;
}
async ackMessage(receiptHandle: string): Promise<any> {
const result = this.nativeClient.ackMessage(this.consumerInfo.consumerId, receiptHandle);
if (!result || typeof result === 'string') {
return { success: true, message: 'Message acknowledged' };
}
if (!result.success) {
throw new Error(`Failed to ack message: ${result.message}`);
}
return result;
}
async shutdown(): Promise<any> {
const result = this.nativeClient.shutdownConsumer(this.consumerInfo.consumerId);
if (!result || typeof result === 'string') {
return { success: true, message: 'Consumer shutdown' };
}
if (!result.success) {
throw new Error(`Failed to shutdown consumer: ${result.message}`);
}
return result;
}
}
// 主客户端类
export class MQClient {
private client: NativeClient;
private initialized: boolean = false;
constructor(config: MQConfig) {
this.client = new NativeClient(config);
}
private async ensureInitialized() {
if (!this.initialized) {
await this.client.initNativeClient();
this.initialized = true;
}
}
/**
* 创建生产者
* @param instanceId 实例ID
* @param topic 主题
* @returns 生产者实例
*/
async getProducer(instanceId: string, topic: string): Promise<Producer> {
await this.ensureInitialized();
return this.client.getProducer(instanceId, topic);
}
/**
* 创建消费者
* @param instanceId 实例ID
* @param topic 主题
* @param groupId 消费者组ID
* @param tagExpression 标签表达式 (默认为'*')
* @returns 消费者实例
*/
async getConsumer(instanceId: string, topic: string, groupId: string, tagExpression: string = '*'): Promise<Consumer> {
await this.ensureInitialized();
return this.client.getConsumer(instanceId, topic, groupId, tagExpression);
}
/**
* 健康检查
*/
async healthCheck(): Promise<any> {
await this.ensureInitialized();
return this.client.healthCheck();
}
/**
* 获取客户端模式
*/
getMode(): string {
return 'native';
}
}
// 导出所有类型和类
export default MQClient;