|
@@ -18,7 +18,8 @@ export class TaskService {
|
|
|
private senderRepository: Repository<Sender>
|
|
private senderRepository: Repository<Sender>
|
|
|
private senderService: SenderService
|
|
private senderService: SenderService
|
|
|
private tgClientService: TgClientService
|
|
private tgClientService: TgClientService
|
|
|
- private readonly senderSendLimit = 5
|
|
|
|
|
|
|
+ private readonly defaultSenderSendLimit = 5
|
|
|
|
|
+ private currentSenderSendLimit = this.defaultSenderSendLimit
|
|
|
private senderUsageInBatch: Map<string, number> = new Map()
|
|
private senderUsageInBatch: Map<string, number> = new Map()
|
|
|
private senderCursor = 0
|
|
private senderCursor = 0
|
|
|
private senderCache: Sender[] = []
|
|
private senderCache: Sender[] = []
|
|
@@ -38,11 +39,18 @@ export class TaskService {
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async create(data: { name: string; message: string; userId: number; buffer: Buffer }): Promise<Task> {
|
|
|
|
|
|
|
+ async create(data: {
|
|
|
|
|
+ name: string
|
|
|
|
|
+ message: string
|
|
|
|
|
+ userId: number
|
|
|
|
|
+ buffer: Buffer
|
|
|
|
|
+ sendLimit?: number
|
|
|
|
|
+ }): Promise<Task> {
|
|
|
const task = this.taskRepository.create({
|
|
const task = this.taskRepository.create({
|
|
|
name: data.name,
|
|
name: data.name,
|
|
|
message: data.message,
|
|
message: data.message,
|
|
|
- userId: data.userId
|
|
|
|
|
|
|
+ userId: data.userId,
|
|
|
|
|
+ sendLimit: data.sendLimit ?? this.defaultSenderSendLimit
|
|
|
})
|
|
})
|
|
|
const savedTask = await this.taskRepository.save(task)
|
|
const savedTask = await this.taskRepository.save(task)
|
|
|
const total = await this.createTaskItemByBuffer({ taskId: savedTask.id, buffer: data.buffer })
|
|
const total = await this.createTaskItemByBuffer({ taskId: savedTask.id, buffer: data.buffer })
|
|
@@ -208,6 +216,13 @@ export class TaskService {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ const configuredSendLimit =
|
|
|
|
|
+ task.sendLimit && Number(task.sendLimit) > 0 ? Number(task.sendLimit) : this.defaultSenderSendLimit
|
|
|
|
|
+
|
|
|
|
|
+ this.currentSenderSendLimit = configuredSendLimit
|
|
|
|
|
+ this.senderUsageInBatch.clear()
|
|
|
|
|
+ this.senderCursor = 0
|
|
|
|
|
+
|
|
|
const pendingItems = await this.taskItemRepository.find({
|
|
const pendingItems = await this.taskItemRepository.find({
|
|
|
where: { taskId: task.id, status: TaskItemStatus.PENDING },
|
|
where: { taskId: task.id, status: TaskItemStatus.PENDING },
|
|
|
order: { id: 'ASC' },
|
|
order: { id: 'ASC' },
|
|
@@ -235,10 +250,6 @@ export class TaskService {
|
|
|
batchSuccess++
|
|
batchSuccess++
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
const msg = error instanceof Error ? error.message : '未知错误'
|
|
const msg = error instanceof Error ? error.message : '未知错误'
|
|
|
- await this.taskItemRepository.update(item.id, {
|
|
|
|
|
- status: TaskItemStatus.FAILED,
|
|
|
|
|
- sentAt: new Date()
|
|
|
|
|
- })
|
|
|
|
|
batchFailed++
|
|
batchFailed++
|
|
|
this.app.log.warn(`发送失败 taskId=${task.id}, item=${item.id}: ${msg}`)
|
|
this.app.log.warn(`发送失败 taskId=${task.id}, item=${item.id}: ${msg}`)
|
|
|
}
|
|
}
|
|
@@ -300,7 +311,9 @@ export class TaskService {
|
|
|
|
|
|
|
|
await this.taskItemRepository.update(taskItem.id, {
|
|
await this.taskItemRepository.update(taskItem.id, {
|
|
|
status: TaskItemStatus.SUCCESS,
|
|
status: TaskItemStatus.SUCCESS,
|
|
|
- sentAt: new Date()
|
|
|
|
|
|
|
+ sentAt: new Date(),
|
|
|
|
|
+ senderId: sender.id,
|
|
|
|
|
+ errorMsg: null
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
await this.senderService.incrementUsageCount(sender.id)
|
|
await this.senderService.incrementUsageCount(sender.id)
|
|
@@ -308,19 +321,28 @@ export class TaskService {
|
|
|
const used = (this.senderUsageInBatch.get(sender.id) ?? 0) + 1
|
|
const used = (this.senderUsageInBatch.get(sender.id) ?? 0) + 1
|
|
|
this.senderUsageInBatch.set(sender.id, used)
|
|
this.senderUsageInBatch.set(sender.id, used)
|
|
|
|
|
|
|
|
- if (used >= this.senderSendLimit) {
|
|
|
|
|
- this.app.log.info(`sender=${sender.id} 已达单次发送上限 ${this.senderSendLimit},切换下一个账号`)
|
|
|
|
|
|
|
+ if (used >= this.currentSenderSendLimit) {
|
|
|
|
|
+ this.app.log.info(`sender=${sender.id} 已达单次发送上限 ${this.currentSenderSendLimit},切换下一个账号`)
|
|
|
await this.tgClientService.disconnect()
|
|
await this.tgClientService.disconnect()
|
|
|
}
|
|
}
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
|
|
+ const msg = error instanceof Error ? error.message : '未知错误'
|
|
|
|
|
+ await this.taskItemRepository.update(taskItem.id, {
|
|
|
|
|
+ status: TaskItemStatus.FAILED,
|
|
|
|
|
+ sentAt: new Date(),
|
|
|
|
|
+ senderId: sender.id,
|
|
|
|
|
+ errorMsg: msg
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
if (client) {
|
|
if (client) {
|
|
|
try {
|
|
try {
|
|
|
await this.tgClientService.disconnect()
|
|
await this.tgClientService.disconnect()
|
|
|
} catch (disconnectError) {
|
|
} catch (disconnectError) {
|
|
|
- const msg = disconnectError instanceof Error ? disconnectError.message : '未知错误'
|
|
|
|
|
- this.app.log.warn(`断开连接失败: ${msg}`)
|
|
|
|
|
|
|
+ const disconnectMsg = disconnectError instanceof Error ? disconnectError.message : '未知错误'
|
|
|
|
|
+ this.app.log.warn(`断开连接失败: ${disconnectMsg}`)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
throw error
|
|
throw error
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -365,7 +387,7 @@ export class TaskService {
|
|
|
const index = (this.senderCursor + i) % total
|
|
const index = (this.senderCursor + i) % total
|
|
|
const sender = this.senderCache[index]
|
|
const sender = this.senderCache[index]
|
|
|
const used = this.senderUsageInBatch.get(sender.id) ?? 0
|
|
const used = this.senderUsageInBatch.get(sender.id) ?? 0
|
|
|
- if (used < this.senderSendLimit) {
|
|
|
|
|
|
|
+ if (used < this.currentSenderSendLimit) {
|
|
|
this.senderCursor = (index + 1) % total
|
|
this.senderCursor = (index + 1) % total
|
|
|
return sender
|
|
return sender
|
|
|
}
|
|
}
|