feat(platform): Fix pg-boss queue conflict and add safety standards
Summary: - Fix pg-boss queue conflict (duplicate key violation on queue_pkey) - Add global error listener to prevent process crash - Reduce connection pool from 10 to 4 - Add graceful shutdown handling (SIGTERM/SIGINT) - Fix researchWorker recursive call bug in catch block - Make screeningWorker idempotent using upsert Security Standards (v1.1): - Prohibit recursive retry in Worker catch blocks - Prohibit payload bloat (only store fileKey/ID in job.data) - Require Worker idempotency (upsert + unique constraint) - Recommend task-specific expireInSeconds settings - Document graceful shutdown pattern New Features: - PKB signed URL endpoint for document preview/download - pg_bigm installation guide for Docker - Dockerfile.postgres-with-extensions for pgvector + pg_bigm Documentation: - Update Postgres-Only async task processing guide (v1.1) - Add troubleshooting SQL queries - Update safety checklist Tested: Local verification passed
This commit is contained in:
@@ -163,5 +163,6 @@ https://iit.xunzhengyixue.com/api/v1/iit/health
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -64,5 +64,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -324,5 +324,6 @@ npx tsx src/modules/iit-manager/test-patient-wechat-url-verify.ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -186,5 +186,6 @@ npm run dev
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -65,3 +65,4 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -59,3 +59,4 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -54,3 +54,4 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -86,3 +86,4 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -49,3 +49,4 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -90,3 +90,4 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -37,3 +37,4 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -125,3 +125,4 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -96,3 +96,4 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -82,3 +82,4 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -124,3 +124,4 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -35,3 +35,4 @@ ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -67,3 +67,4 @@ ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -77,3 +77,4 @@ OSS_INTERNAL=true # 🔴 生产必须用内网
|
||||
OSS_SIGNED_URL_EXPIRES=3600
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -83,5 +83,6 @@ WHERE table_schema = 'dc_schema'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -121,5 +121,6 @@ ORDER BY ordinal_position;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -134,5 +134,6 @@ runMigration()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -68,5 +68,6 @@ COMMENT ON COLUMN "dc_schema"."dc_tool_c_sessions"."column_mapping" IS '列名
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -95,5 +95,6 @@ COMMENT ON COLUMN dc_schema.dc_tool_c_sessions.expires_at IS '过期时间(创
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -65,3 +65,4 @@ USING gin (metadata jsonb_path_ops);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -32,3 +32,4 @@ USING gin (tags);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -135,5 +135,6 @@ Write-Host ""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -245,5 +245,6 @@ function extractCodeBlocks(obj, blocks = []) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -44,3 +44,4 @@ CREATE TABLE IF NOT EXISTS platform_schema.job_common (
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -118,3 +118,4 @@ CREATE OR REPLACE FUNCTION platform_schema.delete_queue(queue_name text) RETURNS
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -264,5 +264,6 @@ checkDCTables();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -19,3 +19,4 @@ CREATE SCHEMA IF NOT EXISTS capability_schema;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -216,5 +216,6 @@ createAiHistoryTable()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -203,5 +203,6 @@ createToolCTable()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -200,5 +200,6 @@ createToolCTable()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -322,3 +322,4 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -129,3 +129,4 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -347,5 +347,6 @@ runTests().catch(error => {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -95,3 +95,4 @@ testAPI().catch(console.error);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -125,3 +125,4 @@ testDeepSearch().catch(console.error);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -312,5 +312,6 @@ verifySchemas()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -202,3 +202,4 @@ export const jwtService = new JWTService();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ export class PgBossQueue implements JobQueue {
|
||||
this.boss = new PgBoss({
|
||||
connectionString,
|
||||
schema, // 使用platform_schema
|
||||
max: 10, // 最大连接数
|
||||
max: 4, // 🛡️ 限制连接数,避免挤占 Prisma 连接配额(RDS 限制 100)
|
||||
application_name: 'aiclinical-queue',
|
||||
|
||||
// 调度配置
|
||||
@@ -61,6 +61,17 @@ export class PgBossQueue implements JobQueue {
|
||||
maintenanceIntervalSeconds: 300, // 每5分钟运行维护任务
|
||||
})
|
||||
|
||||
// 🛡️ 全局错误监听:防止未捕获错误导致进程崩溃
|
||||
this.boss.on('error', (err: any) => {
|
||||
// 静默处理 duplicate key 错误(队列并发初始化时的正常现象)
|
||||
if (err.code === '23505' && err.constraint === 'queue_pkey') {
|
||||
console.log(`[PgBossQueue] ℹ️ Queue concurrency conflict auto-resolved: ${err.detail}`);
|
||||
} else {
|
||||
console.error('[PgBossQueue] ❌ Critical error:', err);
|
||||
// 记录到日志但不崩溃进程
|
||||
}
|
||||
});
|
||||
|
||||
console.log('[PgBossQueue] Initialized with schema:', schema)
|
||||
}
|
||||
|
||||
@@ -192,13 +203,22 @@ export class PgBossQueue implements JobQueue {
|
||||
console.log(`[PgBossQueue] 🔧 开始注册 Handler: ${type}`);
|
||||
|
||||
try {
|
||||
// pg-boss 9.x 需要显式创建队列
|
||||
await this.boss.createQueue(type, {
|
||||
retryLimit: 3,
|
||||
retryDelay: 60,
|
||||
expireInSeconds: 6 * 60 * 60 // 6小时
|
||||
});
|
||||
console.log(`[PgBossQueue] ✅ Queue created: ${type}`);
|
||||
// pg-boss 9.x 需要显式创建队列(幂等操作)
|
||||
try {
|
||||
await this.boss.createQueue(type, {
|
||||
retryLimit: 3,
|
||||
retryDelay: 60,
|
||||
expireInSeconds: 6 * 60 * 60 // 6小时
|
||||
});
|
||||
console.log(`[PgBossQueue] ✅ Queue created: ${type}`);
|
||||
} catch (createError: any) {
|
||||
// 队列已存在时会报 duplicate key 错误,忽略
|
||||
if (createError.code === '23505' || createError.message?.includes('already exists')) {
|
||||
console.log(`[PgBossQueue] ℹ️ Queue already exists: ${type}`);
|
||||
} else {
|
||||
throw createError;
|
||||
}
|
||||
}
|
||||
|
||||
await this.boss.work<Record<string, any>>(type, {
|
||||
batchSize: 1, // 每次处理1个任务
|
||||
|
||||
@@ -332,5 +332,6 @@ export function getBatchItems<T>(
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -85,3 +85,4 @@ export interface VariableValidation {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -355,3 +355,4 @@ export default ChunkService;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -51,3 +51,4 @@ export const DifyClient = DeprecatedDifyClient;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -206,3 +206,4 @@ export function createOpenAIStreamAdapter(
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -212,3 +212,4 @@ export async function streamChat(
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -30,3 +30,4 @@ export { THINKING_TAGS } from './types';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -105,3 +105,4 @@ export type SSEEventType =
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -280,3 +280,33 @@ const start = async () => {
|
||||
};
|
||||
|
||||
start();
|
||||
|
||||
// ============================================
|
||||
// 🛡️ 优雅关闭处理(Graceful Shutdown)
|
||||
// ============================================
|
||||
const gracefulShutdown = async (signal: string) => {
|
||||
console.log(`\n⚠️ 收到 ${signal} 信号,开始优雅关闭...`);
|
||||
|
||||
try {
|
||||
// 1. 停止接收新请求
|
||||
await fastify.close();
|
||||
console.log('✅ HTTP 服务已停止');
|
||||
|
||||
// 2. 停止队列(等待当前任务完成)
|
||||
await jobQueue.stop();
|
||||
console.log('✅ 任务队列已停止');
|
||||
|
||||
// 3. 关闭数据库连接
|
||||
await prisma.$disconnect();
|
||||
console.log('✅ 数据库连接已关闭');
|
||||
|
||||
console.log('👋 优雅关闭完成,再见!');
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ 优雅关闭失败:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
||||
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
||||
|
||||
@@ -91,3 +91,4 @@ export async function moduleRoutes(fastify: FastifyInstance) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -121,3 +121,4 @@ export interface PaginatedResponse<T> {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -168,3 +168,4 @@ export const ROLE_DISPLAY_NAMES: Record<UserRole, string> = {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -243,3 +243,4 @@ async function matchIntent(query: string): Promise<{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -97,3 +97,4 @@ export async function uploadAttachment(
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -26,3 +26,4 @@ export { aiaRoutes };
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -368,5 +368,6 @@ runTests().catch((error) => {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -309,5 +309,6 @@ runTest()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -347,5 +347,6 @@ Content-Type: application/json
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ async function processScreeningBatchWithCheckpoint(
|
||||
literature.publicationYear ? Number(literature.publicationYear) : undefined
|
||||
);
|
||||
|
||||
// 保存结果(使用 screeningService.ts 相同的映射方式)
|
||||
// 保存结果(使用 upsert 保证幂等性,任务重试时覆盖而不是重复创建)
|
||||
const dbResult = {
|
||||
projectId,
|
||||
literatureId: literature.id,
|
||||
@@ -294,8 +294,16 @@ async function processScreeningBatchWithCheckpoint(
|
||||
finalDecision: screeningResult.finalDecision,
|
||||
};
|
||||
|
||||
await prisma.aslScreeningResult.create({
|
||||
data: dbResult,
|
||||
// 🛡️ 使用 upsert 实现幂等性(利用 unique_project_literature 约束)
|
||||
await prisma.aslScreeningResult.upsert({
|
||||
where: {
|
||||
projectId_literatureId: {
|
||||
projectId,
|
||||
literatureId: literature.id,
|
||||
},
|
||||
},
|
||||
create: dbResult,
|
||||
update: dbResult,
|
||||
});
|
||||
|
||||
successCount++;
|
||||
|
||||
@@ -67,12 +67,8 @@ export function registerResearchWorker() {
|
||||
error: error.message,
|
||||
});
|
||||
|
||||
// 更新任务状态为失败
|
||||
try {
|
||||
await researchService.executeSearch(taskId, query);
|
||||
} catch {
|
||||
// 忽略
|
||||
}
|
||||
// ❌ 已移除错误的 executeSearch 调用
|
||||
// 任务失败后 pg-boss 会自动重试(最多3次)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
|
||||
@@ -283,5 +283,6 @@ export const conflictDetectionService = new ConflictDetectionService();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -233,5 +233,6 @@ curl -X POST http://localhost:3000/api/v1/dc/tool-c/test/execute \
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -287,5 +287,6 @@ export const streamAIController = new StreamAIController();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -196,5 +196,6 @@ logger.info('[SessionMemory] 会话记忆管理器已启动', {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -130,5 +130,6 @@ checkTableStructure();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -117,5 +117,6 @@ checkProjectConfig().catch(console.error);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -99,5 +99,6 @@ main();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -556,5 +556,6 @@ URL: https://iit.xunzhengyixue.com/api/v1/iit/patient-wechat/callback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -191,5 +191,6 @@ console.log('');
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -508,5 +508,6 @@ export const patientWechatService = new PatientWechatService();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -153,5 +153,6 @@ testDifyIntegration().catch(error => {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -182,5 +182,6 @@ testIitDatabase()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -168,5 +168,6 @@ if (hasError) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -194,5 +194,6 @@ async function testUrlVerification() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -275,5 +275,6 @@ main().catch((error) => {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -159,5 +159,6 @@ Write-Host ""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -252,5 +252,6 @@ export interface CachedProtocolRules {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import type { FastifyRequest, FastifyReply } from 'fastify';
|
||||
import * as documentService from '../services/documentService.js';
|
||||
import { storage } from '../../../common/storage/index.js';
|
||||
import { OSSAdapter } from '../../../common/storage/OSSAdapter.js';
|
||||
import { randomUUID } from 'crypto';
|
||||
import path from 'path';
|
||||
import { logger } from '../../../common/logging/index.js';
|
||||
|
||||
/**
|
||||
* 获取用户ID(从JWT Token中获取)
|
||||
@@ -374,4 +376,93 @@ export async function getDocumentFullText(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文档签名URL(用于前端预览/下载)
|
||||
*
|
||||
* @description
|
||||
* 生成一个带有过期时间的签名URL,前端可以直接使用该URL:
|
||||
* - 在浏览器中预览 PDF
|
||||
* - 下载文件(会恢复原始文件名)
|
||||
*/
|
||||
export async function getDocumentSignedUrl(
|
||||
request: FastifyRequest<{
|
||||
Params: {
|
||||
id: string;
|
||||
};
|
||||
Querystring: {
|
||||
/** 过期时间(秒),默认3600秒 */
|
||||
expires?: string;
|
||||
/** 是否作为附件下载(添加 Content-Disposition),默认 false */
|
||||
download?: string;
|
||||
};
|
||||
}>,
|
||||
reply: FastifyReply
|
||||
) {
|
||||
try {
|
||||
const { id } = request.params;
|
||||
const expires = parseInt(request.query.expires || '3600', 10);
|
||||
const download = request.query.download === 'true';
|
||||
|
||||
const userId = getUserId(request);
|
||||
|
||||
// 获取文档信息
|
||||
const document = await documentService.getDocumentById(userId, id);
|
||||
|
||||
// 检查是否有存储路径
|
||||
if (!document.storageKey) {
|
||||
logger.warn('[PKB] 文档没有存储路径,可能是旧数据', { documentId: id });
|
||||
return reply.status(404).send({
|
||||
success: false,
|
||||
message: '文档文件不可用,请重新上传',
|
||||
});
|
||||
}
|
||||
|
||||
// 生成签名URL
|
||||
let signedUrl: string;
|
||||
|
||||
// 检查存储适配器类型
|
||||
if (storage instanceof OSSAdapter) {
|
||||
// OSS: 使用带原始文件名的签名URL
|
||||
signedUrl = download
|
||||
? storage.getSignedUrl(document.storageKey, expires, document.filename)
|
||||
: storage.getSignedUrl(document.storageKey, expires);
|
||||
} else {
|
||||
// 本地存储: 使用 getUrl
|
||||
signedUrl = storage.getUrl(document.storageKey);
|
||||
}
|
||||
|
||||
logger.info('[PKB] 生成签名URL', {
|
||||
documentId: id,
|
||||
filename: document.filename,
|
||||
expires,
|
||||
download
|
||||
});
|
||||
|
||||
return reply.send({
|
||||
success: true,
|
||||
data: {
|
||||
documentId: document.id,
|
||||
filename: document.filename,
|
||||
fileType: document.fileType,
|
||||
url: signedUrl,
|
||||
expiresIn: expires,
|
||||
},
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error('[PKB] 获取签名URL失败', { error: error.message });
|
||||
|
||||
if (error.message.includes('not found') || error.message.includes('access denied')) {
|
||||
return reply.status(404).send({
|
||||
success: false,
|
||||
message: error.message,
|
||||
});
|
||||
}
|
||||
|
||||
return reply.status(500).send({
|
||||
success: false,
|
||||
message: error.message || 'Failed to get signed URL',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -65,5 +65,6 @@ export default async function healthRoutes(fastify: FastifyInstance) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -44,6 +44,10 @@ export default async function knowledgeBaseRoutes(fastify: FastifyInstance) {
|
||||
// Phase 2: 获取文档全文
|
||||
fastify.get('/documents/:id/full-text', { preHandler: [authenticate, requireModule('PKB')] }, documentController.getDocumentFullText);
|
||||
|
||||
// 获取文档签名URL(用于预览/下载)
|
||||
// Query: ?expires=3600&download=true
|
||||
fastify.get('/documents/:id/signed-url', { preHandler: [authenticate, requireModule('PKB')] }, documentController.getDocumentSignedUrl);
|
||||
|
||||
// 删除文档
|
||||
fastify.delete('/documents/:id', { preHandler: [authenticate, requireModule('PKB')] }, documentController.deleteDocument);
|
||||
|
||||
|
||||
@@ -143,5 +143,6 @@ Content-Type: application/json
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -128,5 +128,6 @@ Write-Host " - 删除任务: DELETE $BaseUrl/api/v1/rvw/tasks/{taskId}" -Foregr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -42,5 +42,6 @@ export * from './services/utils.js';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -133,5 +133,6 @@ export function validateAgentSelection(agents: string[]): void {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -433,5 +433,6 @@ SET session_replication_role = 'origin';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -113,3 +113,4 @@ testCrossLanguageSearch();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -175,3 +175,4 @@ testQueryRewrite();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -121,3 +121,4 @@ testRerank();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -135,5 +135,6 @@ WHERE key = 'verify_test';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -278,5 +278,6 @@ verifyDatabase()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1
backend/src/types/global.d.ts
vendored
1
backend/src/types/global.d.ts
vendored
@@ -68,5 +68,6 @@ export {}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -91,5 +91,6 @@ Write-Host "✅ 完成!" -ForegroundColor Green
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -18,3 +18,4 @@ SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('p
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -179,5 +179,6 @@ DELETE {{baseUrl}}/api/v1/pkb/knowledge/knowledge-bases/{{testKbId}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -378,5 +378,6 @@ runAdvancedTests().catch(error => {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -444,5 +444,6 @@ runAllTests()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -402,5 +402,6 @@ runAllTests()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -38,3 +38,4 @@ main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user