Skip to content

Commit bdc560a

Browse files
author
linyuan.yang
committed
scheduler
1 parent 26c5453 commit bdc560a

3 files changed

Lines changed: 26 additions & 18 deletions

File tree

packages/sbot/src/Scheduler/SchedulerService.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,16 +146,35 @@ class SchedulerService {
146146
this.executor.stopAll();
147147
}
148148

149+
/** 列出 scheduler,附 nextRun。disabled 默认排除 */
150+
async list(opts?: { includeDisabled?: boolean }): Promise<(SchedulerRow & { nextRun: number | null })[]> {
151+
const where = opts?.includeDisabled ? {} : { disabled: false };
152+
const rows = await database.findAll<SchedulerRow>(database.scheduler, { where });
153+
return rows.map(r => ({ ...(r as any), nextRun: this.nextDate(r.id) }));
154+
}
155+
149156
async delete(schedulerId: number): Promise<void> {
150157
this.executor.cancel(schedulerId);
151158
await database.update(database.scheduler, { disabled: true }, { where: { id: schedulerId } });
152159
}
153160

161+
/** 删除 profile 名下所有 scheduler(cancel cron + 硬删行)—— profile/session 删除时调用 */
162+
async cascadeDeleteByProfile(profileId: number): Promise<void> {
163+
const rows = await database.findAll<SchedulerRow>(database.scheduler, { where: { profileId } });
164+
for (const r of rows) this.executor.cancel(r.id);
165+
await database.destroy(database.scheduler, { where: { profileId } });
166+
}
167+
154168
async update(schedulerId: number, patch: Partial<Pick<SchedulerRow, "message" | "channelSessionId" | "aiProcess">>): Promise<SchedulerRow | null> {
155169
const fields: Partial<SchedulerRow> = {};
156-
if (patch.message != null) fields.message = patch.message;
157-
if (patch.channelSessionId != null) fields.channelSessionId = patch.channelSessionId;
158-
if (patch.aiProcess != null) fields.aiProcess = patch.aiProcess;
170+
if (patch.message != null) fields.message = patch.message;
171+
if (patch.aiProcess != null) fields.aiProcess = patch.aiProcess;
172+
if (patch.channelSessionId != null) {
173+
// 改投递目标时 profileId 必须同步到新 session 的 profile,否则 list/delete 工具按 profileId 过滤会失配
174+
const session = await getChannelSession(patch.channelSessionId, true);
175+
fields.channelSessionId = patch.channelSessionId;
176+
fields.profileId = session!.profileId;
177+
}
159178
if (Object.keys(fields).length === 0) return database.findByPk<SchedulerRow>(database.scheduler, schedulerId);
160179
await database.update(database.scheduler, fields, { where: { id: schedulerId } });
161180
return database.findByPk<SchedulerRow>(database.scheduler, schedulerId);

packages/sbot/src/Server/routes/schedulers.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
import express from 'express';
2-
import { database, type SchedulerRow } from '../../Core/Database';
32
import { schedulerService } from '../../Scheduler/SchedulerService';
43
import { api, throwBad, toPlain } from '../utils';
54
import type { RouteContext } from './types';
65

76
export class SchedulerRoutes {
87
register(app: express.Application, _ctx: RouteContext): void {
98
app.get('/api/schedulers', api(async () => {
10-
const schedulers = await database.findAll<SchedulerRow>(database.scheduler, { where: { disabled: false } });
11-
return schedulers.map(s => ({
12-
...toPlain(s),
13-
nextRun: schedulerService.nextDate(s.id),
14-
}));
9+
const rows = await schedulerService.list();
10+
return rows.map(r => ({ ...toPlain(r), nextRun: r.nextRun }));
1511
}));
1612

1713
app.put('/api/schedulers/:id', api(async req => {

packages/sbot/src/Server/routes/users.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,7 @@ export class UserRoutes {
161161
if (isNaN(id)) throwBad('Invalid id');
162162
// auto profile 会被级联删 —— 上面挂的 scheduler 也跟着销毁
163163
const auto = await database.findOne<SessionProfileRow>(database.sessionProfile, { where: { autoForSessionId: id } });
164-
if (auto) {
165-
const rows = await database.findAll<{ id: number }>(database.scheduler, { where: { profileId: auto.id } });
166-
for (const r of rows) await schedulerService.delete(r.id);
167-
await database.destroy(database.scheduler, { where: { profileId: auto.id } });
168-
}
164+
if (auto) await schedulerService.cascadeDeleteByProfile(auto.id);
169165
// 级联删除该 session 的 auto profile(visible profile 不删)
170166
await database.destroy(database.sessionProfile, { where: { autoForSessionId: id } });
171167
await database.destroy(database.channelSession, { where: { id } });
@@ -238,10 +234,7 @@ export class UserRoutes {
238234
if (profile!.autoForSessionId != null) throwBad('Cannot delete an auto profile directly');
239235
const refCount = await database.count(database.channelSession, { where: { profileId: id } });
240236
if (refCount > 0) throwBad(`Profile id=${id} is still referenced by ${refCount} session(s)`);
241-
// 级联删除 profile 名下的 scheduler(取消 cron + 删行)
242-
const schedRows = await database.findAll<{ id: number }>(database.scheduler, { where: { profileId: id } });
243-
for (const r of schedRows) await schedulerService.delete(r.id);
244-
await database.destroy(database.scheduler, { where: { profileId: id } });
237+
await schedulerService.cascadeDeleteByProfile(id);
245238
await database.destroy(database.sessionProfile, { where: { id } });
246239
}));
247240

0 commit comments

Comments
 (0)