feat(transaction): 添加游戏事务系统 | add game transaction system (#381)
- TransactionManager/TransactionContext 事务管理 - MemoryStorage/RedisStorage/MongoStorage 存储实现 - CurrencyOperation/InventoryOperation/TradeOperation 内置操作 - SagaOrchestrator 分布式 Saga 编排 - withTransactions() Room 集成 - 完整中英文文档
This commit is contained in:
286
packages/framework/transaction/src/core/TransactionContext.ts
Normal file
286
packages/framework/transaction/src/core/TransactionContext.ts
Normal file
@@ -0,0 +1,286 @@
|
||||
/**
|
||||
* @zh 事务上下文实现
|
||||
* @en Transaction context implementation
|
||||
*/
|
||||
|
||||
import type {
|
||||
ITransactionContext,
|
||||
ITransactionOperation,
|
||||
ITransactionStorage,
|
||||
TransactionState,
|
||||
TransactionResult,
|
||||
TransactionOptions,
|
||||
TransactionLog,
|
||||
OperationLog,
|
||||
OperationResult,
|
||||
} from './types.js'
|
||||
|
||||
/**
|
||||
* @zh 生成唯一 ID
|
||||
* @en Generate unique ID
|
||||
*/
|
||||
function generateId(): string {
|
||||
return `tx_${Date.now().toString(36)}_${Math.random().toString(36).substring(2, 11)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 事务上下文
|
||||
* @en Transaction context
|
||||
*
|
||||
* @zh 封装事务的状态、操作和执行逻辑
|
||||
* @en Encapsulates transaction state, operations, and execution logic
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const ctx = new TransactionContext({ timeout: 5000 })
|
||||
* ctx.addOperation(new DeductCurrency({ playerId: '1', amount: 100 }))
|
||||
* ctx.addOperation(new AddItem({ playerId: '1', itemId: 'sword' }))
|
||||
* const result = await ctx.execute()
|
||||
* ```
|
||||
*/
|
||||
export class TransactionContext implements ITransactionContext {
|
||||
private _id: string
|
||||
private _state: TransactionState = 'pending'
|
||||
private _timeout: number
|
||||
private _operations: ITransactionOperation[] = []
|
||||
private _storage: ITransactionStorage | null
|
||||
private _metadata: Record<string, unknown>
|
||||
private _contextData: Map<string, unknown> = new Map()
|
||||
private _startTime: number = 0
|
||||
private _distributed: boolean
|
||||
|
||||
constructor(options: TransactionOptions & { storage?: ITransactionStorage } = {}) {
|
||||
this._id = generateId()
|
||||
this._timeout = options.timeout ?? 30000
|
||||
this._storage = options.storage ?? null
|
||||
this._metadata = options.metadata ?? {}
|
||||
this._distributed = options.distributed ?? false
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 只读属性 | Readonly properties
|
||||
// =========================================================================
|
||||
|
||||
get id(): string {
|
||||
return this._id
|
||||
}
|
||||
|
||||
get state(): TransactionState {
|
||||
return this._state
|
||||
}
|
||||
|
||||
get timeout(): number {
|
||||
return this._timeout
|
||||
}
|
||||
|
||||
get operations(): ReadonlyArray<ITransactionOperation> {
|
||||
return this._operations
|
||||
}
|
||||
|
||||
get storage(): ITransactionStorage | null {
|
||||
return this._storage
|
||||
}
|
||||
|
||||
get metadata(): Record<string, unknown> {
|
||||
return this._metadata
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 公共方法 | Public methods
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* @zh 添加操作
|
||||
* @en Add operation
|
||||
*/
|
||||
addOperation<T extends ITransactionOperation>(operation: T): this {
|
||||
if (this._state !== 'pending') {
|
||||
throw new Error(`Cannot add operation to transaction in state: ${this._state}`)
|
||||
}
|
||||
this._operations.push(operation)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 执行事务
|
||||
* @en Execute transaction
|
||||
*/
|
||||
async execute<T = unknown>(): Promise<TransactionResult<T>> {
|
||||
if (this._state !== 'pending') {
|
||||
return {
|
||||
success: false,
|
||||
transactionId: this._id,
|
||||
results: [],
|
||||
error: `Transaction already in state: ${this._state}`,
|
||||
duration: 0,
|
||||
}
|
||||
}
|
||||
|
||||
this._startTime = Date.now()
|
||||
this._state = 'executing'
|
||||
|
||||
const results: OperationResult[] = []
|
||||
let executedCount = 0
|
||||
|
||||
try {
|
||||
await this._saveLog()
|
||||
|
||||
for (let i = 0; i < this._operations.length; i++) {
|
||||
if (this._isTimedOut()) {
|
||||
throw new Error('Transaction timed out')
|
||||
}
|
||||
|
||||
const op = this._operations[i]
|
||||
|
||||
const isValid = await op.validate(this)
|
||||
if (!isValid) {
|
||||
throw new Error(`Validation failed for operation: ${op.name}`)
|
||||
}
|
||||
|
||||
const result = await op.execute(this)
|
||||
results.push(result)
|
||||
executedCount++
|
||||
|
||||
await this._updateOperationLog(i, 'executed')
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error ?? `Operation ${op.name} failed`)
|
||||
}
|
||||
}
|
||||
|
||||
this._state = 'committed'
|
||||
await this._updateTransactionState('committed')
|
||||
|
||||
return {
|
||||
success: true,
|
||||
transactionId: this._id,
|
||||
results,
|
||||
data: this._collectResultData(results) as T,
|
||||
duration: Date.now() - this._startTime,
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
|
||||
await this._compensate(executedCount - 1)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
transactionId: this._id,
|
||||
results,
|
||||
error: errorMessage,
|
||||
duration: Date.now() - this._startTime,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 手动回滚事务
|
||||
* @en Manually rollback transaction
|
||||
*/
|
||||
async rollback(): Promise<void> {
|
||||
if (this._state === 'committed' || this._state === 'rolledback') {
|
||||
return
|
||||
}
|
||||
|
||||
await this._compensate(this._operations.length - 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 获取上下文数据
|
||||
* @en Get context data
|
||||
*/
|
||||
get<T>(key: string): T | undefined {
|
||||
return this._contextData.get(key) as T | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 设置上下文数据
|
||||
* @en Set context data
|
||||
*/
|
||||
set<T>(key: string, value: T): void {
|
||||
this._contextData.set(key, value)
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 私有方法 | Private methods
|
||||
// =========================================================================
|
||||
|
||||
private _isTimedOut(): boolean {
|
||||
return Date.now() - this._startTime > this._timeout
|
||||
}
|
||||
|
||||
private async _compensate(fromIndex: number): Promise<void> {
|
||||
this._state = 'rolledback'
|
||||
|
||||
for (let i = fromIndex; i >= 0; i--) {
|
||||
const op = this._operations[i]
|
||||
try {
|
||||
await op.compensate(this)
|
||||
await this._updateOperationLog(i, 'compensated')
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
await this._updateOperationLog(i, 'failed', errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
await this._updateTransactionState('rolledback')
|
||||
}
|
||||
|
||||
private async _saveLog(): Promise<void> {
|
||||
if (!this._storage) return
|
||||
|
||||
const log: TransactionLog = {
|
||||
id: this._id,
|
||||
state: this._state,
|
||||
createdAt: this._startTime,
|
||||
updatedAt: this._startTime,
|
||||
timeout: this._timeout,
|
||||
operations: this._operations.map((op) => ({
|
||||
name: op.name,
|
||||
data: op.data,
|
||||
state: 'pending' as const,
|
||||
})),
|
||||
metadata: this._metadata,
|
||||
distributed: this._distributed,
|
||||
}
|
||||
|
||||
await this._storage.saveTransaction(log)
|
||||
}
|
||||
|
||||
private async _updateTransactionState(state: TransactionState): Promise<void> {
|
||||
this._state = state
|
||||
if (this._storage) {
|
||||
await this._storage.updateTransactionState(this._id, state)
|
||||
}
|
||||
}
|
||||
|
||||
private async _updateOperationLog(
|
||||
index: number,
|
||||
state: OperationLog['state'],
|
||||
error?: string
|
||||
): Promise<void> {
|
||||
if (this._storage) {
|
||||
await this._storage.updateOperationState(this._id, index, state, error)
|
||||
}
|
||||
}
|
||||
|
||||
private _collectResultData(results: OperationResult[]): unknown {
|
||||
const data: Record<string, unknown> = {}
|
||||
for (const result of results) {
|
||||
if (result.data !== undefined) {
|
||||
Object.assign(data, result.data)
|
||||
}
|
||||
}
|
||||
return Object.keys(data).length > 0 ? data : undefined
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 创建事务上下文
|
||||
* @en Create transaction context
|
||||
*/
|
||||
export function createTransactionContext(
|
||||
options: TransactionOptions & { storage?: ITransactionStorage } = {}
|
||||
): ITransactionContext {
|
||||
return new TransactionContext(options)
|
||||
}
|
||||
255
packages/framework/transaction/src/core/TransactionManager.ts
Normal file
255
packages/framework/transaction/src/core/TransactionManager.ts
Normal file
@@ -0,0 +1,255 @@
|
||||
/**
|
||||
* @zh 事务管理器
|
||||
* @en Transaction manager
|
||||
*/
|
||||
|
||||
import type {
|
||||
ITransactionContext,
|
||||
ITransactionStorage,
|
||||
TransactionManagerConfig,
|
||||
TransactionOptions,
|
||||
TransactionLog,
|
||||
TransactionResult,
|
||||
} from './types.js'
|
||||
import { TransactionContext } from './TransactionContext.js'
|
||||
|
||||
/**
|
||||
* @zh 事务管理器
|
||||
* @en Transaction manager
|
||||
*
|
||||
* @zh 管理事务的创建、执行和恢复
|
||||
* @en Manages transaction creation, execution, and recovery
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const manager = new TransactionManager({
|
||||
* storage: new RedisStorage({ url: 'redis://localhost:6379' }),
|
||||
* defaultTimeout: 10000,
|
||||
* })
|
||||
*
|
||||
* const tx = manager.begin({ timeout: 5000 })
|
||||
* tx.addOperation(new DeductCurrency({ ... }))
|
||||
* tx.addOperation(new AddItem({ ... }))
|
||||
*
|
||||
* const result = await tx.execute()
|
||||
* ```
|
||||
*/
|
||||
export class TransactionManager {
|
||||
private _storage: ITransactionStorage | null
|
||||
private _defaultTimeout: number
|
||||
private _serverId: string
|
||||
private _autoRecover: boolean
|
||||
private _activeTransactions: Map<string, ITransactionContext> = new Map()
|
||||
|
||||
constructor(config: TransactionManagerConfig = {}) {
|
||||
this._storage = config.storage ?? null
|
||||
this._defaultTimeout = config.defaultTimeout ?? 30000
|
||||
this._serverId = config.serverId ?? this._generateServerId()
|
||||
this._autoRecover = config.autoRecover ?? true
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 只读属性 | Readonly properties
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* @zh 服务器 ID
|
||||
* @en Server ID
|
||||
*/
|
||||
get serverId(): string {
|
||||
return this._serverId
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 存储实例
|
||||
* @en Storage instance
|
||||
*/
|
||||
get storage(): ITransactionStorage | null {
|
||||
return this._storage
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 活跃事务数量
|
||||
* @en Active transaction count
|
||||
*/
|
||||
get activeCount(): number {
|
||||
return this._activeTransactions.size
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 公共方法 | Public methods
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* @zh 开始新事务
|
||||
* @en Begin new transaction
|
||||
*
|
||||
* @param options - @zh 事务选项 @en Transaction options
|
||||
* @returns @zh 事务上下文 @en Transaction context
|
||||
*/
|
||||
begin(options: TransactionOptions = {}): ITransactionContext {
|
||||
const ctx = new TransactionContext({
|
||||
timeout: options.timeout ?? this._defaultTimeout,
|
||||
storage: this._storage ?? undefined,
|
||||
metadata: {
|
||||
...options.metadata,
|
||||
serverId: this._serverId,
|
||||
},
|
||||
distributed: options.distributed,
|
||||
})
|
||||
|
||||
this._activeTransactions.set(ctx.id, ctx)
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 执行事务(便捷方法)
|
||||
* @en Execute transaction (convenience method)
|
||||
*
|
||||
* @param builder - @zh 事务构建函数 @en Transaction builder function
|
||||
* @param options - @zh 事务选项 @en Transaction options
|
||||
* @returns @zh 事务结果 @en Transaction result
|
||||
*/
|
||||
async run<T = unknown>(
|
||||
builder: (ctx: ITransactionContext) => void | Promise<void>,
|
||||
options: TransactionOptions = {}
|
||||
): Promise<TransactionResult<T>> {
|
||||
const ctx = this.begin(options)
|
||||
|
||||
try {
|
||||
await builder(ctx)
|
||||
const result = await ctx.execute<T>()
|
||||
return result
|
||||
} finally {
|
||||
this._activeTransactions.delete(ctx.id)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 获取活跃事务
|
||||
* @en Get active transaction
|
||||
*/
|
||||
getTransaction(id: string): ITransactionContext | undefined {
|
||||
return this._activeTransactions.get(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 恢复未完成的事务
|
||||
* @en Recover pending transactions
|
||||
*/
|
||||
async recover(): Promise<number> {
|
||||
if (!this._storage) return 0
|
||||
|
||||
const pendingTransactions = await this._storage.getPendingTransactions(this._serverId)
|
||||
let recoveredCount = 0
|
||||
|
||||
for (const log of pendingTransactions) {
|
||||
try {
|
||||
await this._recoverTransaction(log)
|
||||
recoveredCount++
|
||||
} catch (error) {
|
||||
console.error(`Failed to recover transaction ${log.id}:`, error)
|
||||
}
|
||||
}
|
||||
|
||||
return recoveredCount
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 获取分布式锁
|
||||
* @en Acquire distributed lock
|
||||
*/
|
||||
async acquireLock(key: string, ttl: number = 10000): Promise<string | null> {
|
||||
if (!this._storage) return null
|
||||
return this._storage.acquireLock(key, ttl)
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 释放分布式锁
|
||||
* @en Release distributed lock
|
||||
*/
|
||||
async releaseLock(key: string, token: string): Promise<boolean> {
|
||||
if (!this._storage) return false
|
||||
return this._storage.releaseLock(key, token)
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 使用分布式锁执行
|
||||
* @en Execute with distributed lock
|
||||
*/
|
||||
async withLock<T>(
|
||||
key: string,
|
||||
fn: () => Promise<T>,
|
||||
ttl: number = 10000
|
||||
): Promise<T> {
|
||||
const token = await this.acquireLock(key, ttl)
|
||||
if (!token) {
|
||||
throw new Error(`Failed to acquire lock for key: ${key}`)
|
||||
}
|
||||
|
||||
try {
|
||||
return await fn()
|
||||
} finally {
|
||||
await this.releaseLock(key, token)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 清理已完成的事务日志
|
||||
* @en Clean up completed transaction logs
|
||||
*/
|
||||
async cleanup(beforeTimestamp?: number): Promise<number> {
|
||||
if (!this._storage) return 0
|
||||
|
||||
const timestamp = beforeTimestamp ?? Date.now() - 24 * 60 * 60 * 1000 // 默认清理24小时前
|
||||
|
||||
const pendingTransactions = await this._storage.getPendingTransactions()
|
||||
let cleanedCount = 0
|
||||
|
||||
for (const log of pendingTransactions) {
|
||||
if (
|
||||
log.createdAt < timestamp &&
|
||||
(log.state === 'committed' || log.state === 'rolledback')
|
||||
) {
|
||||
await this._storage.deleteTransaction(log.id)
|
||||
cleanedCount++
|
||||
}
|
||||
}
|
||||
|
||||
return cleanedCount
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 私有方法 | Private methods
|
||||
// =========================================================================
|
||||
|
||||
private _generateServerId(): string {
|
||||
return `server_${Date.now().toString(36)}_${Math.random().toString(36).substring(2, 8)}`
|
||||
}
|
||||
|
||||
private async _recoverTransaction(log: TransactionLog): Promise<void> {
|
||||
if (log.state === 'executing') {
|
||||
const executedOps = log.operations.filter((op) => op.state === 'executed')
|
||||
|
||||
if (executedOps.length > 0 && this._storage) {
|
||||
for (let i = executedOps.length - 1; i >= 0; i--) {
|
||||
await this._storage.updateOperationState(log.id, i, 'compensated')
|
||||
}
|
||||
await this._storage.updateTransactionState(log.id, 'rolledback')
|
||||
} else {
|
||||
await this._storage?.updateTransactionState(log.id, 'failed')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 创建事务管理器
|
||||
* @en Create transaction manager
|
||||
*/
|
||||
export function createTransactionManager(
|
||||
config: TransactionManagerConfig = {}
|
||||
): TransactionManager {
|
||||
return new TransactionManager(config)
|
||||
}
|
||||
20
packages/framework/transaction/src/core/index.ts
Normal file
20
packages/framework/transaction/src/core/index.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @zh 核心模块导出
|
||||
* @en Core module exports
|
||||
*/
|
||||
|
||||
export type {
|
||||
TransactionState,
|
||||
OperationResult,
|
||||
TransactionResult,
|
||||
OperationLog,
|
||||
TransactionLog,
|
||||
TransactionOptions,
|
||||
TransactionManagerConfig,
|
||||
ITransactionStorage,
|
||||
ITransactionOperation,
|
||||
ITransactionContext,
|
||||
} from './types.js'
|
||||
|
||||
export { TransactionContext, createTransactionContext } from './TransactionContext.js'
|
||||
export { TransactionManager, createTransactionManager } from './TransactionManager.js'
|
||||
484
packages/framework/transaction/src/core/types.ts
Normal file
484
packages/framework/transaction/src/core/types.ts
Normal file
@@ -0,0 +1,484 @@
|
||||
/**
|
||||
* @zh 事务系统核心类型定义
|
||||
* @en Transaction system core type definitions
|
||||
*/
|
||||
|
||||
// =============================================================================
|
||||
// 事务状态 | Transaction State
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @zh 事务状态
|
||||
* @en Transaction state
|
||||
*/
|
||||
export type TransactionState =
|
||||
| 'pending' // 等待执行 | Waiting to execute
|
||||
| 'executing' // 执行中 | Executing
|
||||
| 'committed' // 已提交 | Committed
|
||||
| 'rolledback' // 已回滚 | Rolled back
|
||||
| 'failed' // 失败 | Failed
|
||||
|
||||
// =============================================================================
|
||||
// 操作结果 | Operation Result
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @zh 操作结果
|
||||
* @en Operation result
|
||||
*/
|
||||
export interface OperationResult<T = unknown> {
|
||||
/**
|
||||
* @zh 是否成功
|
||||
* @en Whether succeeded
|
||||
*/
|
||||
success: boolean
|
||||
|
||||
/**
|
||||
* @zh 返回数据
|
||||
* @en Return data
|
||||
*/
|
||||
data?: T
|
||||
|
||||
/**
|
||||
* @zh 错误信息
|
||||
* @en Error message
|
||||
*/
|
||||
error?: string
|
||||
|
||||
/**
|
||||
* @zh 错误代码
|
||||
* @en Error code
|
||||
*/
|
||||
errorCode?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 事务结果
|
||||
* @en Transaction result
|
||||
*/
|
||||
export interface TransactionResult<T = unknown> {
|
||||
/**
|
||||
* @zh 是否成功
|
||||
* @en Whether succeeded
|
||||
*/
|
||||
success: boolean
|
||||
|
||||
/**
|
||||
* @zh 事务 ID
|
||||
* @en Transaction ID
|
||||
*/
|
||||
transactionId: string
|
||||
|
||||
/**
|
||||
* @zh 操作结果列表
|
||||
* @en Operation results
|
||||
*/
|
||||
results: OperationResult[]
|
||||
|
||||
/**
|
||||
* @zh 最终数据
|
||||
* @en Final data
|
||||
*/
|
||||
data?: T
|
||||
|
||||
/**
|
||||
* @zh 错误信息
|
||||
* @en Error message
|
||||
*/
|
||||
error?: string
|
||||
|
||||
/**
|
||||
* @zh 执行时间(毫秒)
|
||||
* @en Execution time in milliseconds
|
||||
*/
|
||||
duration: number
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 事务日志 | Transaction Log
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @zh 操作日志
|
||||
* @en Operation log
|
||||
*/
|
||||
export interface OperationLog {
|
||||
/**
|
||||
* @zh 操作名称
|
||||
* @en Operation name
|
||||
*/
|
||||
name: string
|
||||
|
||||
/**
|
||||
* @zh 操作数据
|
||||
* @en Operation data
|
||||
*/
|
||||
data: unknown
|
||||
|
||||
/**
|
||||
* @zh 操作状态
|
||||
* @en Operation state
|
||||
*/
|
||||
state: 'pending' | 'executed' | 'compensated' | 'failed'
|
||||
|
||||
/**
|
||||
* @zh 执行时间
|
||||
* @en Execution timestamp
|
||||
*/
|
||||
executedAt?: number
|
||||
|
||||
/**
|
||||
* @zh 补偿时间
|
||||
* @en Compensation timestamp
|
||||
*/
|
||||
compensatedAt?: number
|
||||
|
||||
/**
|
||||
* @zh 错误信息
|
||||
* @en Error message
|
||||
*/
|
||||
error?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 事务日志
|
||||
* @en Transaction log
|
||||
*/
|
||||
export interface TransactionLog {
|
||||
/**
|
||||
* @zh 事务 ID
|
||||
* @en Transaction ID
|
||||
*/
|
||||
id: string
|
||||
|
||||
/**
|
||||
* @zh 事务状态
|
||||
* @en Transaction state
|
||||
*/
|
||||
state: TransactionState
|
||||
|
||||
/**
|
||||
* @zh 创建时间
|
||||
* @en Creation timestamp
|
||||
*/
|
||||
createdAt: number
|
||||
|
||||
/**
|
||||
* @zh 更新时间
|
||||
* @en Update timestamp
|
||||
*/
|
||||
updatedAt: number
|
||||
|
||||
/**
|
||||
* @zh 超时时间(毫秒)
|
||||
* @en Timeout in milliseconds
|
||||
*/
|
||||
timeout: number
|
||||
|
||||
/**
|
||||
* @zh 操作日志列表
|
||||
* @en Operation logs
|
||||
*/
|
||||
operations: OperationLog[]
|
||||
|
||||
/**
|
||||
* @zh 元数据
|
||||
* @en Metadata
|
||||
*/
|
||||
metadata?: Record<string, unknown>
|
||||
|
||||
/**
|
||||
* @zh 是否分布式事务
|
||||
* @en Whether distributed transaction
|
||||
*/
|
||||
distributed?: boolean
|
||||
|
||||
/**
|
||||
* @zh 参与的服务器列表
|
||||
* @en Participating servers
|
||||
*/
|
||||
participants?: string[]
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 事务配置 | Transaction Configuration
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @zh 事务选项
|
||||
* @en Transaction options
|
||||
*/
|
||||
export interface TransactionOptions {
|
||||
/**
|
||||
* @zh 超时时间(毫秒),默认 30000
|
||||
* @en Timeout in milliseconds, default 30000
|
||||
*/
|
||||
timeout?: number
|
||||
|
||||
/**
|
||||
* @zh 是否分布式事务
|
||||
* @en Whether distributed transaction
|
||||
*/
|
||||
distributed?: boolean
|
||||
|
||||
/**
|
||||
* @zh 元数据
|
||||
* @en Metadata
|
||||
*/
|
||||
metadata?: Record<string, unknown>
|
||||
|
||||
/**
|
||||
* @zh 重试次数,默认 0
|
||||
* @en Retry count, default 0
|
||||
*/
|
||||
retryCount?: number
|
||||
|
||||
/**
|
||||
* @zh 重试间隔(毫秒),默认 1000
|
||||
* @en Retry interval in milliseconds, default 1000
|
||||
*/
|
||||
retryInterval?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 事务管理器配置
|
||||
* @en Transaction manager configuration
|
||||
*/
|
||||
export interface TransactionManagerConfig {
|
||||
/**
|
||||
* @zh 存储实例
|
||||
* @en Storage instance
|
||||
*/
|
||||
storage?: ITransactionStorage
|
||||
|
||||
/**
|
||||
* @zh 默认超时时间(毫秒)
|
||||
* @en Default timeout in milliseconds
|
||||
*/
|
||||
defaultTimeout?: number
|
||||
|
||||
/**
|
||||
* @zh 服务器 ID(分布式用)
|
||||
* @en Server ID for distributed transactions
|
||||
*/
|
||||
serverId?: string
|
||||
|
||||
/**
|
||||
* @zh 是否自动恢复未完成事务
|
||||
* @en Whether to auto-recover pending transactions
|
||||
*/
|
||||
autoRecover?: boolean
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 存储接口 | Storage Interface
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @zh 事务存储接口
|
||||
* @en Transaction storage interface
|
||||
*/
|
||||
export interface ITransactionStorage {
|
||||
/**
|
||||
* @zh 获取分布式锁
|
||||
* @en Acquire distributed lock
|
||||
*
|
||||
* @param key - @zh 锁的键 @en Lock key
|
||||
* @param ttl - @zh 锁的生存时间(毫秒) @en Lock TTL in milliseconds
|
||||
* @returns @zh 锁令牌,获取失败返回 null @en Lock token, null if failed
|
||||
*/
|
||||
acquireLock(key: string, ttl: number): Promise<string | null>
|
||||
|
||||
/**
|
||||
* @zh 释放分布式锁
|
||||
* @en Release distributed lock
|
||||
*
|
||||
* @param key - @zh 锁的键 @en Lock key
|
||||
* @param token - @zh 锁令牌 @en Lock token
|
||||
* @returns @zh 是否成功释放 @en Whether released successfully
|
||||
*/
|
||||
releaseLock(key: string, token: string): Promise<boolean>
|
||||
|
||||
/**
|
||||
* @zh 保存事务日志
|
||||
* @en Save transaction log
|
||||
*/
|
||||
saveTransaction(tx: TransactionLog): Promise<void>
|
||||
|
||||
/**
|
||||
* @zh 获取事务日志
|
||||
* @en Get transaction log
|
||||
*/
|
||||
getTransaction(id: string): Promise<TransactionLog | null>
|
||||
|
||||
/**
|
||||
* @zh 更新事务状态
|
||||
* @en Update transaction state
|
||||
*/
|
||||
updateTransactionState(id: string, state: TransactionState): Promise<void>
|
||||
|
||||
/**
|
||||
* @zh 更新操作状态
|
||||
* @en Update operation state
|
||||
*/
|
||||
updateOperationState(
|
||||
transactionId: string,
|
||||
operationIndex: number,
|
||||
state: OperationLog['state'],
|
||||
error?: string
|
||||
): Promise<void>
|
||||
|
||||
/**
|
||||
* @zh 获取待恢复的事务列表
|
||||
* @en Get pending transactions for recovery
|
||||
*/
|
||||
getPendingTransactions(serverId?: string): Promise<TransactionLog[]>
|
||||
|
||||
/**
|
||||
* @zh 删除事务日志
|
||||
* @en Delete transaction log
|
||||
*/
|
||||
deleteTransaction(id: string): Promise<void>
|
||||
|
||||
/**
|
||||
* @zh 获取数据
|
||||
* @en Get data
|
||||
*/
|
||||
get<T>(key: string): Promise<T | null>
|
||||
|
||||
/**
|
||||
* @zh 设置数据
|
||||
* @en Set data
|
||||
*/
|
||||
set<T>(key: string, value: T, ttl?: number): Promise<void>
|
||||
|
||||
/**
|
||||
* @zh 删除数据
|
||||
* @en Delete data
|
||||
*/
|
||||
delete(key: string): Promise<boolean>
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 操作接口 | Operation Interface
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @zh 事务操作接口
|
||||
* @en Transaction operation interface
|
||||
*/
|
||||
export interface ITransactionOperation<TData = unknown, TResult = unknown> {
|
||||
/**
|
||||
* @zh 操作名称
|
||||
* @en Operation name
|
||||
*/
|
||||
readonly name: string
|
||||
|
||||
/**
|
||||
* @zh 操作数据
|
||||
* @en Operation data
|
||||
*/
|
||||
readonly data: TData
|
||||
|
||||
/**
|
||||
* @zh 验证前置条件
|
||||
* @en Validate preconditions
|
||||
*
|
||||
* @param ctx - @zh 事务上下文 @en Transaction context
|
||||
* @returns @zh 是否验证通过 @en Whether validation passed
|
||||
*/
|
||||
validate(ctx: ITransactionContext): Promise<boolean>
|
||||
|
||||
/**
|
||||
* @zh 执行操作
|
||||
* @en Execute operation
|
||||
*
|
||||
* @param ctx - @zh 事务上下文 @en Transaction context
|
||||
* @returns @zh 操作结果 @en Operation result
|
||||
*/
|
||||
execute(ctx: ITransactionContext): Promise<OperationResult<TResult>>
|
||||
|
||||
/**
|
||||
* @zh 补偿操作(回滚)
|
||||
* @en Compensate operation (rollback)
|
||||
*
|
||||
* @param ctx - @zh 事务上下文 @en Transaction context
|
||||
*/
|
||||
compensate(ctx: ITransactionContext): Promise<void>
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 事务上下文接口 | Transaction Context Interface
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @zh 事务上下文接口
|
||||
* @en Transaction context interface
|
||||
*/
|
||||
export interface ITransactionContext {
|
||||
/**
|
||||
* @zh 事务 ID
|
||||
* @en Transaction ID
|
||||
*/
|
||||
readonly id: string
|
||||
|
||||
/**
|
||||
* @zh 事务状态
|
||||
* @en Transaction state
|
||||
*/
|
||||
readonly state: TransactionState
|
||||
|
||||
/**
|
||||
* @zh 超时时间(毫秒)
|
||||
* @en Timeout in milliseconds
|
||||
*/
|
||||
readonly timeout: number
|
||||
|
||||
/**
|
||||
* @zh 操作列表
|
||||
* @en Operations
|
||||
*/
|
||||
readonly operations: ReadonlyArray<ITransactionOperation>
|
||||
|
||||
/**
|
||||
* @zh 存储实例
|
||||
* @en Storage instance
|
||||
*/
|
||||
readonly storage: ITransactionStorage | null
|
||||
|
||||
/**
|
||||
* @zh 元数据
|
||||
* @en Metadata
|
||||
*/
|
||||
readonly metadata: Record<string, unknown>
|
||||
|
||||
/**
|
||||
* @zh 添加操作
|
||||
* @en Add operation
|
||||
*/
|
||||
addOperation<T extends ITransactionOperation>(operation: T): this
|
||||
|
||||
/**
|
||||
* @zh 执行事务
|
||||
* @en Execute transaction
|
||||
*/
|
||||
execute<T = unknown>(): Promise<TransactionResult<T>>
|
||||
|
||||
/**
|
||||
* @zh 回滚事务
|
||||
* @en Rollback transaction
|
||||
*/
|
||||
rollback(): Promise<void>
|
||||
|
||||
/**
|
||||
* @zh 获取上下文数据
|
||||
* @en Get context data
|
||||
*/
|
||||
get<T>(key: string): T | undefined
|
||||
|
||||
/**
|
||||
* @zh 设置上下文数据
|
||||
* @en Set context data
|
||||
*/
|
||||
set<T>(key: string, value: T): void
|
||||
}
|
||||
Reference in New Issue
Block a user