已改成后台“检查并发布”任务,原来的超时主要就是同步逐条校验导致的。
发布接口立即返回 202 Accepted,页面轮询显示检查进度。 校验改为批量读取,减少重复数据库查询。 检查失败保留草稿并显示具体原因;成功后原子完成旧课表归档和新课表发布。 同一学期禁止两个发布任务并发,服务重启后未完成任务会自动恢复。 发布期间锁定编辑、自动排课等冲突操作。 已补齐 SQLite 开发迁移及 MySQL 生产迁移。
This commit is contained in:
@@ -27,6 +27,8 @@ public sealed class DevelopmentSqliteMigrator(
|
||||
"20260724_16_automatic_schedule_jobs";
|
||||
private const string TeachingTaskSchedulingModesMigration =
|
||||
"20260725_17_teaching_task_scheduling_modes";
|
||||
private const string SchedulePublishJobsMigration =
|
||||
"20260725_18_schedule_publish_jobs";
|
||||
|
||||
public async Task MigrateAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -163,6 +165,18 @@ public sealed class DevelopmentSqliteMigrator(
|
||||
TeachingTaskSchedulingModesMigration,
|
||||
teachingTaskSchedulingModeExists ? [] : TeachingTaskSchedulingModeStatements,
|
||||
cancellationToken);
|
||||
var schedulePublishJobsExist = await db.Database
|
||||
.SqlQueryRaw<int>(
|
||||
"""
|
||||
SELECT COUNT(*) AS "Value"
|
||||
FROM sqlite_master
|
||||
WHERE type = 'table' AND name = 'SchedulePublishJobs'
|
||||
""")
|
||||
.AnyAsync(value => value > 0, cancellationToken);
|
||||
await ApplyMigrationAsync(
|
||||
SchedulePublishJobsMigration,
|
||||
schedulePublishJobsExist ? [] : SchedulePublishJobStatements,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
private async Task ApplyMigrationAsync(
|
||||
@@ -1104,4 +1118,48 @@ public sealed class DevelopmentSqliteMigrator(
|
||||
ADD COLUMN "SchedulingMode" INTEGER NOT NULL DEFAULT 1;
|
||||
"""
|
||||
];
|
||||
|
||||
private static readonly string[] SchedulePublishJobStatements =
|
||||
[
|
||||
"""
|
||||
CREATE TABLE "SchedulePublishJobs" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_SchedulePublishJobs" PRIMARY KEY,
|
||||
"SchedulePlanId" TEXT NOT NULL,
|
||||
"AcademicTermId" TEXT NOT NULL,
|
||||
"ActiveAcademicTermId" TEXT NULL,
|
||||
"RequestedByUserId" TEXT NULL,
|
||||
"Status" INTEGER NOT NULL,
|
||||
"TotalSteps" INTEGER NOT NULL,
|
||||
"CompletedSteps" INTEGER NOT NULL,
|
||||
"CurrentStep" TEXT NULL,
|
||||
"ErrorMessage" TEXT NULL,
|
||||
"StartedAt" TEXT NULL,
|
||||
"CompletedAt" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
CONSTRAINT "FK_SchedulePublishJobs_SchedulePlans"
|
||||
FOREIGN KEY ("SchedulePlanId") REFERENCES "SchedulePlans" ("Id")
|
||||
ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_SchedulePublishJobs_RequestedBy"
|
||||
FOREIGN KEY ("RequestedByUserId") REFERENCES "AspNetUsers" ("Id")
|
||||
ON DELETE SET NULL
|
||||
);
|
||||
""",
|
||||
"""
|
||||
CREATE UNIQUE INDEX "IX_SchedulePublishJobs_ActiveAcademicTermId"
|
||||
ON "SchedulePublishJobs" ("ActiveAcademicTermId");
|
||||
""",
|
||||
"""
|
||||
CREATE INDEX "IX_SchedulePublishJobs_SchedulePlanId_CreatedAt"
|
||||
ON "SchedulePublishJobs" ("SchedulePlanId", "CreatedAt");
|
||||
""",
|
||||
"""
|
||||
CREATE INDEX "IX_SchedulePublishJobs_Status_CreatedAt"
|
||||
ON "SchedulePublishJobs" ("Status", "CreatedAt");
|
||||
""",
|
||||
"""
|
||||
CREATE INDEX "IX_SchedulePublishJobs_RequestedByUserId"
|
||||
ON "SchedulePublishJobs" ("RequestedByUserId");
|
||||
"""
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user