cnpmcore
Version:
250 lines • 21.6 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChangesStreamService = void 0;
const os_1 = __importDefault(require("os"));
const promises_1 = require("timers/promises");
const tegg_1 = require("@eggjs/tegg");
const Task_1 = require("../../common/enum/Task");
const AbstractService_1 = require("../../common/AbstractService");
const TaskRepository_1 = require("../../repository/TaskRepository");
const Task_2 = require("../entity/Task");
const PackageSyncerService_1 = require("./PackageSyncerService");
const TaskService_1 = require("./TaskService");
const RegistryManagerService_1 = require("./RegistryManagerService");
const egg_errors_1 = require("egg-errors");
const AbstractChangesStream_1 = require("../../common/adapter/changesStream/AbstractChangesStream");
const PackageUtil_1 = require("../../common/PackageUtil");
const constants_1 = require("../../common/constants");
const ScopeManagerService_1 = require("./ScopeManagerService");
const PackageRepository_1 = require("../../repository/PackageRepository");
let ChangesStreamService = class ChangesStreamService extends AbstractService_1.AbstractService {
// 出于向下兼容考虑, changes_stream 类型 Task 分为
// GLOBAL_WORKER: 默认的同步源
// `{registryName}_WORKER`: 自定义 scope 的同步源
async findExecuteTask() {
const targetName = constants_1.GLOBAL_WORKER;
const globalRegistryTask = await this.taskRepository.findTaskByTargetName(targetName, Task_1.TaskType.ChangesStream);
// 如果没有配置默认同步源,先进行初始化
if (!globalRegistryTask) {
await this.taskService.createTask(Task_2.Task.createChangesStream(targetName), false);
}
// 自定义 scope 由 admin 手动创建
// 根据 TaskType.ChangesStream 从队列中获取
return await this.taskService.findExecuteTask(Task_1.TaskType.ChangesStream);
}
async suspendSync(exit = false) {
this.logger.info('[ChangesStreamService.suspendSync:start]');
if (this.config.cnpmcore.enableChangesStream) {
// 防止继续获取新的任务
if (exit) {
this.config.cnpmcore.enableChangesStream = false;
}
const authorIp = os_1.default.hostname();
// 暂停当前机器所有的 changesStream 任务
const tasks = await this.taskRepository.findTaskByAuthorIpAndType(authorIp, Task_1.TaskType.ChangesStream);
for (const task of tasks) {
if (task.state === Task_1.TaskState.Processing) {
this.logger.info('[ChangesStreamService.suspendSync:suspend] taskId: %s', task.taskId);
// 1. 更新任务状态为 waiting
// 2. 重新推入任务队列供其他机器执行
await this.taskService.retryTask(task);
}
}
}
this.logger.info('[ChangesStreamService.suspendSync:finish]');
}
async executeTask(task) {
task.authorIp = os_1.default.hostname();
task.authorId = `pid_${process.pid}`;
await this.taskRepository.saveTask(task);
// 初始化 changeStream 任务
// since 默认从 1 开始
try {
let since = task.data.since;
if (!since) {
since = await this.getInitialSince(task);
}
// allow disable changesStream dynamic
while (since && this.config.cnpmcore.enableChangesStream) {
const { lastSince, taskCount } = await this.executeSync(since, task);
this.logger.info('[ChangesStreamService.executeTask:changes] since: %s => %s, %d new tasks, taskId: %s, updatedAt: %j', since, lastSince, taskCount, task.taskId, task.updatedAt);
since = lastSince;
if (taskCount === 0 && this.config.env === 'unittest') {
break;
}
await (0, promises_1.setTimeout)(this.config.cnpmcore.checkChangesStreamInterval);
}
}
catch (err) {
this.logger.warn('[ChangesStreamService.executeTask:error] %s, exit now', err.message);
if (err.name === 'HttpClientRequestTimeoutError'
|| err.name === 'ConnectTimeoutError'
|| err.name === 'BodyTimeoutError') {
this.logger.warn(err);
}
else {
this.logger.error(err);
}
task.error = `${err}`;
await this.taskRepository.saveTask(task);
await this.suspendSync();
}
}
// 优先从 registryId 获取,如果没有的话再返回默认的 registry
async prepareRegistry(task) {
const { registryId } = task.data || {};
// 如果已有 registryId, 查询 DB 直接获取
if (registryId) {
const registry = await this.registryManagerService.findByRegistryId(registryId);
if (!registry) {
this.logger.error('[ChangesStreamService.getRegistry:error] registryId %s not found', registryId);
throw new egg_errors_1.E500(`invalid change stream registry: ${registryId}`);
}
return registry;
}
const registry = await this.registryManagerService.ensureDefaultRegistry();
task.data = {
...(task.data || {}),
registryId: registry.registryId,
};
await this.taskRepository.saveTask(task);
return registry;
}
// 根据 regsitry 判断是否需要添加同步任务
// 1. 如果该包已经指定了 registryId 则以 registryId 为准
// 1. 该包的 scope 在当前 registry 下
// 2. 如果 registry 下没有配置 scope (认为是通用 registry 地址) ,且该包的 scope 不在其他 registry 下
async needSync(registry, fullname) {
const [scopeName, name] = (0, PackageUtil_1.getScopeAndName)(fullname);
const packageEntity = await this.packageRepository.findPackage(scopeName, name);
// 如果包不存在,且处在 exist 模式下,则不同步
if (this.config.cnpmcore.syncMode === 'exist' && !packageEntity) {
return false;
}
if (packageEntity?.registryId) {
return registry.registryId === packageEntity.registryId;
}
const scope = await this.scopeManagerService.findByName(scopeName);
const inCurrentRegistry = scope && scope?.registryId === registry.registryId;
if (inCurrentRegistry) {
return true;
}
const registryScopeCount = await this.scopeManagerService.countByRegistryId(registry.registryId);
// 当前包没有 scope 信息,且当前 registry 下没有 scope,是通用 registry,需要同步
return !scope && !registryScopeCount;
}
async getInitialSince(task) {
const registry = await this.prepareRegistry(task);
const changesStreamAdapter = await this.eggObjectFactory.getEggObject(AbstractChangesStream_1.AbstractChangeStream, registry.type);
const since = await changesStreamAdapter.getInitialSince(registry);
return since;
}
// 从 changesStream 获取需要同步的数据
// 更新任务的 since 和 taskCount 相关字段
async executeSync(since, task) {
const registry = await this.prepareRegistry(task);
const changesStreamAdapter = await this.eggObjectFactory.getEggObject(AbstractChangesStream_1.AbstractChangeStream, registry.type);
let taskCount = 0;
let lastSince = since;
// 获取需要同步的数据
// 需要根据 scope 和包信息进行过滤
const stream = changesStreamAdapter.fetchChanges(registry, since);
let lastPackage;
// 创建同步任务
for await (const change of stream) {
const { fullname, seq } = change;
lastPackage = fullname;
lastSince = seq;
const valid = await this.needSync(registry, fullname);
if (valid) {
taskCount++;
const tips = `Sync cause by changes_stream(${registry.changeStream}) update seq: ${seq}`;
try {
const task = await this.packageSyncerService.createTask(fullname, {
authorIp: Task_2.HOST_NAME,
authorId: 'ChangesStreamService',
registryId: registry.registryId,
skipDependencies: true,
tips,
});
this.logger.info('[ChangesStreamService.createTask:success] fullname: %s, task: %s, tips: %s', fullname, task.id, tips);
}
catch (err) {
if (err instanceof PackageSyncerService_1.RegistryNotMatchError) {
this.logger.warn('[ChangesStreamService.executeSync:skip] fullname: %s, error: %s, tips: %s', fullname, err, tips);
continue;
}
// only log error, make sure changes still reading
this.logger.error('[ChangesStreamService.executeSync:error] fullname: %s, error: %s, tips: %s', fullname, err, tips);
this.logger.error(err);
continue;
}
}
// 实时更新 task 信息
// 即使不需要同步,防止任务处理累积耗时超过 10min
task.updateSyncData({
lastSince,
lastPackage,
taskCount,
});
await this.taskRepository.saveTask(task);
}
// 如果 taskCount 为 0 更新一下任务信息
if (taskCount === 0) {
task.updateSyncData({
lastSince,
lastPackage,
taskCount,
});
await this.taskRepository.saveTask(task);
}
return { lastSince, taskCount };
}
};
exports.ChangesStreamService = ChangesStreamService;
__decorate([
(0, tegg_1.Inject)(),
__metadata("design:type", TaskRepository_1.TaskRepository)
], ChangesStreamService.prototype, "taskRepository", void 0);
__decorate([
(0, tegg_1.Inject)(),
__metadata("design:type", PackageSyncerService_1.PackageSyncerService)
], ChangesStreamService.prototype, "packageSyncerService", void 0);
__decorate([
(0, tegg_1.Inject)(),
__metadata("design:type", TaskService_1.TaskService)
], ChangesStreamService.prototype, "taskService", void 0);
__decorate([
(0, tegg_1.Inject)(),
__metadata("design:type", RegistryManagerService_1.RegistryManagerService)
], ChangesStreamService.prototype, "registryManagerService", void 0);
__decorate([
(0, tegg_1.Inject)(),
__metadata("design:type", ScopeManagerService_1.ScopeManagerService)
], ChangesStreamService.prototype, "scopeManagerService", void 0);
__decorate([
(0, tegg_1.Inject)(),
__metadata("design:type", Object)
], ChangesStreamService.prototype, "eggObjectFactory", void 0);
__decorate([
(0, tegg_1.Inject)(),
__metadata("design:type", PackageRepository_1.PackageRepository)
], ChangesStreamService.prototype, "packageRepository", void 0);
exports.ChangesStreamService = ChangesStreamService = __decorate([
(0, tegg_1.SingletonProto)({
accessLevel: tegg_1.AccessLevel.PUBLIC,
})
], ChangesStreamService);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2hhbmdlc1N0cmVhbVNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9hcHAvY29yZS9zZXJ2aWNlL0NoYW5nZXNTdHJlYW1TZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDRDQUFvQjtBQUNwQiw4Q0FBNkM7QUFDN0Msc0NBS3FCO0FBQ3JCLGlEQUE2RDtBQUM3RCxrRUFBK0Q7QUFDL0Qsb0VBQWlFO0FBQ2pFLHlDQUFvRTtBQUNwRSxpRUFBcUY7QUFDckYsK0NBQTRDO0FBQzVDLHFFQUFrRTtBQUNsRSwyQ0FBa0M7QUFFbEMsb0dBQWdHO0FBQ2hHLDBEQUEyRDtBQUMzRCxzREFBdUQ7QUFDdkQsK0RBQTREO0FBQzVELDBFQUF1RTtBQUtoRSxJQUFNLG9CQUFvQixHQUExQixNQUFNLG9CQUFxQixTQUFRLGlDQUFlO0lBZ0J2RCxzQ0FBc0M7SUFDdEMsd0JBQXdCO0lBQ3hCLDBDQUEwQztJQUNuQyxLQUFLLENBQUMsZUFBZTtRQUMxQixNQUFNLFVBQVUsR0FBRyx5QkFBYSxDQUFDO1FBQ2pDLE1BQU0sa0JBQWtCLEdBQUcsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLG9CQUFvQixDQUFDLFVBQVUsRUFBRSxlQUFRLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDOUcscUJBQXFCO1FBQ3JCLElBQUksQ0FBQyxrQkFBa0IsRUFBRTtZQUN2QixNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLFdBQUksQ0FBQyxtQkFBbUIsQ0FBQyxVQUFVLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztTQUNoRjtRQUNELHlCQUF5QjtRQUN6QixtQ0FBbUM7UUFDbkMsT0FBTyxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsZUFBZSxDQUFDLGVBQVEsQ0FBQyxhQUFhLENBQXNCLENBQUM7SUFDN0YsQ0FBQztJQUVNLEtBQUssQ0FBQyxXQUFXLENBQUMsSUFBSSxHQUFHLEtBQUs7UUFD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