MicProtocol / apps /api /dist /admin /admin-operations.service.js
Benaah's picture
Upload folder using huggingface_hub
303c85f verified
Raw History Blame Contribute Delete
11.7 kB
"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 __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var AdminOperationsService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminOperationsService = exports.OPERATIONS_QUEUES = void 0;
const common_1 = require("@nestjs/common");
const bullmq_1 = require("@nestjs/bullmq");
const common_2 = require("@nestjs/common");
const prisma_service_1 = require("../prisma/prisma.service");
const audit_service_1 = require("../audit/audit.service");
const cache_service_1 = require("../common/cache/cache.service");
const redis_constants_1 = require("../common/redis.constants");
const shared_types_1 = require("@micprotocol/shared-types");
const admin_permission_decorator_1 = require("../common/decorators/admin-permission.decorator");
exports.OPERATIONS_QUEUES = [
"outreach",
"content",
"notifications",
"analytics",
"network",
"post-interview",
"clip-scoring",
"email",
"reminder",
"asset-processing",
"outreach-automation",
"verification",
];
let AdminOperationsService = AdminOperationsService_1 = class AdminOperationsService {
prisma;
audit;
cache;
redis;
outreachQueue;
contentQueue;
notificationsQueue;
analyticsQueue;
networkQueue;
postInterviewQueue;
clipScoringQueue;
emailQueue;
reminderQueue;
assetProcessingQueue;
outreachAutomationQueue;
verificationQueue;
logger = new common_1.Logger(AdminOperationsService_1.name);
constructor(prisma, audit, cache, redis, outreachQueue, contentQueue, notificationsQueue, analyticsQueue, networkQueue, postInterviewQueue, clipScoringQueue, emailQueue, reminderQueue, assetProcessingQueue, outreachAutomationQueue, verificationQueue) {
this.prisma = prisma;
this.audit = audit;
this.cache = cache;
this.redis = redis;
this.outreachQueue = outreachQueue;
this.contentQueue = contentQueue;
this.notificationsQueue = notificationsQueue;
this.analyticsQueue = analyticsQueue;
this.networkQueue = networkQueue;
this.postInterviewQueue = postInterviewQueue;
this.clipScoringQueue = clipScoringQueue;
this.emailQueue = emailQueue;
this.reminderQueue = reminderQueue;
this.assetProcessingQueue = assetProcessingQueue;
this.outreachAutomationQueue = outreachAutomationQueue;
this.verificationQueue = verificationQueue;
}
queueByName(name) {
const queues = {
outreach: this.outreachQueue,
content: this.contentQueue,
notifications: this.notificationsQueue,
analytics: this.analyticsQueue,
network: this.networkQueue,
"post-interview": this.postInterviewQueue,
"clip-scoring": this.clipScoringQueue,
email: this.emailQueue,
reminder: this.reminderQueue,
"asset-processing": this.assetProcessingQueue,
"outreach-automation": this.outreachAutomationQueue,
verification: this.verificationQueue,
};
const queue = queues[name];
if (!queue)
throw new common_1.NotFoundException(`Unknown queue ${name}`);
return queue;
}
async getQueueHealth() {
const results = [];
for (const name of exports.OPERATIONS_QUEUES) {
const queue = this.queueByName(name);
const [waiting, active, completed, failed, delayed] = await Promise.all([
queue.getWaitingCount(),
queue.getActiveCount(),
queue.getCompletedCount(),
queue.getFailedCount(),
queue.getDelayedCount(),
]);
results.push({ name, waiting, active, completed, failed, delayed });
}
return results.sort((a, b) => b.failed - a.failed || b.waiting - a.waiting);
}
async getQueueJobs(queueName, type, limit = 50) {
const queue = this.queueByName(queueName);
const getJobs = queue[`get${type.charAt(0).toUpperCase() + type.slice(1)}`];
const jobs = await getJobs.call(queue, 0, Math.min(limit, 200));
return jobs.map((job) => ({
id: job.id,
type: job.name,
progress: job.progress,
failedReason: job.failedReason,
createdAt: job.timestamp ? new Date(job.timestamp) : null,
}));
}
async retryJob(queueName, jobId, actorUserId) {
const queue = this.queueByName(queueName);
const job = await queue.getJob(jobId);
if (!job)
throw new common_1.NotFoundException(`Job ${jobId} not found in queue ${queueName}`);
await job.retry();
await this.audit.log({
userId: actorUserId,
action: "admin.ops.retry_jobs",
entityType: "Job",
entityId: jobId,
metadata: { queue: queueName, jobType: job.name },
});
return { retried: jobId, queue: queueName };
}
async purgeFailedJobs(queueName, actorUserId) {
const queue = this.queueByName(queueName);
const failed = await queue.getFailed();
let removed = 0;
for (const job of failed) {
await job.remove();
removed++;
}
await this.audit.log({
userId: actorUserId,
action: "admin.ops.purge_jobs",
entityType: "Queue",
entityId: queueName,
metadata: { removed, type: "failed" },
});
return { purged: removed, queue: queueName };
}
async getLocks(pattern = "lock:clip:*", limit = 100) {
const keys = await this.redis.keys(pattern);
const sample = keys.slice(0, limit);
return { pattern, total: keys.length, keys: sample };
}
async releaseLock(key, actorUserId) {
const deleted = await this.redis.del(key);
await this.audit.log({
userId: actorUserId,
action: "admin.ops.locks",
entityType: "Lock",
entityId: key,
metadata: { deleted },
});
return { key, deleted };
}
async getSystemHealth() {
let database = "down";
let redis = "down";
try {
await this.prisma.$queryRawUnsafe("SELECT 1");
database = "up";
}
catch {
database = "down";
}
try {
await this.redis.ping();
redis = "up";
}
catch {
redis = "down";
}
const overall = database === "up" && redis === "up" ? "up" : database === "down" && redis === "down" ? "down" : "degraded";
return { database, redis, overall };
}
async setMaintenanceMode(enabled, actorUserId) {
const setting = await this.prisma.platformSetting.upsert({
where: { key: "maintenance.mode" },
update: {
value: enabled,
updatedById: actorUserId,
},
create: {
key: "maintenance.mode",
value: enabled,
description: "Platform maintenance mode — signups and writes are rejected when enabled",
category: "operations",
updatedById: actorUserId,
},
});
await this.audit.log({
userId: actorUserId,
action: "admin.ops.maintenance",
entityType: "PlatformSetting",
entityId: "maintenance.mode",
metadata: { before: null, after: enabled },
});
return setting;
}
async flushCache(pattern, actorUserId) {
await this.cache.delPattern(pattern);
await this.audit.log({
userId: actorUserId,
action: "admin.ops.cache",
entityType: "Cache",
entityId: pattern,
metadata: { pattern },
});
return { flushed: pattern };
}
};
exports.AdminOperationsService = AdminOperationsService;
__decorate([
(0, admin_permission_decorator_1.requireAdminPermission)(shared_types_1.AdminPermission.OPS_RETRY_JOBS),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, String, String]),
__metadata("design:returntype", Promise)
], AdminOperationsService.prototype, "retryJob", null);
__decorate([
(0, admin_permission_decorator_1.requireAdminPermission)(shared_types_1.AdminPermission.OPS_PURGE_JOBS),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, String]),
__metadata("design:returntype", Promise)
], AdminOperationsService.prototype, "purgeFailedJobs", null);
__decorate([
(0, admin_permission_decorator_1.requireAdminPermission)(shared_types_1.AdminPermission.OPS_LOCKS),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, String]),
__metadata("design:returntype", Promise)
], AdminOperationsService.prototype, "releaseLock", null);
__decorate([
(0, admin_permission_decorator_1.requireAdminPermission)(shared_types_1.AdminPermission.OPS_MAINTENANCE),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Boolean, String]),
__metadata("design:returntype", Promise)
], AdminOperationsService.prototype, "setMaintenanceMode", null);
__decorate([
(0, admin_permission_decorator_1.requireAdminPermission)(shared_types_1.AdminPermission.OPS_CACHE),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, String]),
__metadata("design:returntype", Promise)
], AdminOperationsService.prototype, "flushCache", null);
exports.AdminOperationsService = AdminOperationsService = AdminOperationsService_1 = __decorate([
(0, common_1.Injectable)(),
__param(3, (0, common_2.Inject)(redis_constants_1.REDIS_CLIENT)),
__param(4, (0, bullmq_1.InjectQueue)("outreach")),
__param(5, (0, bullmq_1.InjectQueue)("content")),
__param(6, (0, bullmq_1.InjectQueue)("notifications")),
__param(7, (0, bullmq_1.InjectQueue)("analytics")),
__param(8, (0, bullmq_1.InjectQueue)("network")),
__param(9, (0, bullmq_1.InjectQueue)("post-interview")),
__param(10, (0, bullmq_1.InjectQueue)("clip-scoring")),
__param(11, (0, bullmq_1.InjectQueue)("email")),
__param(12, (0, bullmq_1.InjectQueue)("reminder")),
__param(13, (0, bullmq_1.InjectQueue)("asset-processing")),
__param(14, (0, bullmq_1.InjectQueue)("outreach-automation")),
__param(15, (0, bullmq_1.InjectQueue)("verification")),
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
audit_service_1.AuditService,
cache_service_1.CacheService, Object, Function, Function, Function, Function, Function, Function, Function, Function, Function, Function, Function, Function])
], AdminOperationsService);
//# sourceMappingURL=admin-operations.service.js.map