Files
kiss-translator/src/libs/pool.js

171 lines
3.7 KiB
JavaScript
Raw Normal View History

import { DEFAULT_FETCH_INTERVAL, DEFAULT_FETCH_LIMIT } from "../config";
2024-03-19 18:07:18 +08:00
import { kissLog } from "./log";
2023-08-20 19:27:29 +08:00
/**
* 任务池
*/
2025-09-03 22:07:49 +08:00
class TaskPool {
#pool = [];
#maxRetry = 2; // 最大重试次数
#retryInterval = 1000; // 重试间隔时间
#limit; // 最大并发数
#interval; // 任务最小启动间隔
#currentConcurrent = 0; // 当前正在执行的任务数
#lastExecutionTime = 0; // 上一个任务的启动时间
#schedulerTimer = null; // 用于调度下一个任务的定时器
constructor(
interval = DEFAULT_FETCH_INTERVAL,
limit = DEFAULT_FETCH_LIMIT,
retryInterval = 1000
) {
this.#interval = interval;
this.#limit = limit;
this.#retryInterval = retryInterval;
}
/**
* 调度器
*/
#scheduleNext() {
if (this.#schedulerTimer) {
return;
2023-08-04 16:05:14 +08:00
}
2025-09-03 22:07:49 +08:00
if (this.#currentConcurrent >= this.#limit || this.#pool.length === 0) {
return;
}
const now = Date.now();
const timeSinceLast = now - this.#lastExecutionTime;
const delay = Math.max(0, this.#interval - timeSinceLast);
this.#schedulerTimer = setTimeout(() => {
this.#schedulerTimer = null;
if (this.#currentConcurrent < this.#limit && this.#pool.length > 0) {
const task = this.#pool.shift();
if (task) {
this.#lastExecutionTime = Date.now();
this.#execute(task);
}
2023-08-11 16:48:09 +08:00
}
2025-09-03 22:07:49 +08:00
if (this.#pool.length > 0) {
this.#scheduleNext();
2023-08-04 16:05:14 +08:00
}
2025-09-03 22:07:49 +08:00
}, delay);
}
/**
* 执行单个任务
* @param {object} task - 任务对象
*/
async #execute(task) {
this.#currentConcurrent++;
const { fn, args, resolve, reject, retry } = task;
try {
const res = await fn(args);
resolve(res);
} catch (err) {
kissLog("task pool", err);
2025-09-03 22:07:49 +08:00
if (retry < this.#maxRetry) {
setTimeout(() => {
this.#pool.unshift({ ...task, retry: retry + 1 }); // unshift 保证重试任务优先
this.#scheduleNext();
}, this.#retryInterval);
} else {
reject(err);
2023-08-04 16:05:14 +08:00
}
2025-09-03 22:07:49 +08:00
} finally {
this.#currentConcurrent--;
this.#scheduleNext();
}
}
/**
* 向任务池中添加一个新任务
* @param {Function} fn - 要执行的异步函数
* @param {*} args - 函数的参数
* @returns {Promise}
*/
push(fn, args) {
return new Promise((resolve, reject) => {
this.#pool.push({ fn, args, resolve, reject, retry: 0 });
this.#scheduleNext();
});
}
/**
* 更新任务池的配置
* @param {number} interval - 新的最小任务间隔
* @param {number} limit - 新的最大并发数
*/
update(interval, limit) {
if (interval >= 0) {
this.#interval = interval;
}
if (limit >= 1) {
this.#limit = limit;
}
this.#scheduleNext();
}
/**
* 清空任务池
*/
clear() {
for (const task of this.#pool) {
task.reject("the task pool was cleared");
}
this.#pool.length = 0;
if (this.#schedulerTimer) {
clearTimeout(this.#schedulerTimer);
this.#schedulerTimer = null;
}
}
}
/**
* 请求池实例
*/
let fetchPool;
/**
* 获取请求池实例
2025-09-03 22:07:49 +08:00
* @param interval
* @param limit
2025-09-01 18:56:48 +08:00
* @returns
*/
export const getFetchPool = (interval, limit) => {
if (!fetchPool) {
2025-09-03 22:07:49 +08:00
fetchPool = new TaskPool(
interval ?? DEFAULT_FETCH_INTERVAL,
limit ?? DEFAULT_FETCH_LIMIT
);
} else if (interval && limit) {
updateFetchPool(interval, limit);
}
return fetchPool;
};
/**
* 更新请求池参数
* @param {*} interval
* @param {*} limit
*/
export const updateFetchPool = (interval, limit) => {
2025-09-03 22:07:49 +08:00
fetchPool?.update(interval, limit);
};
/**
* 清空请求池
*/
export const clearFetchPool = () => {
2025-09-03 22:07:49 +08:00
fetchPool?.clear();
};