diff --git a/back/api/cron.ts b/back/api/cron.ts index 90777f85..2dc7e5f2 100644 --- a/back/api/cron.ts +++ b/back/api/cron.ts @@ -176,6 +176,7 @@ export default (app: Router) => { name: Joi.string().optional(), labels: Joi.array().optional(), sub_id: Joi.number().optional().allow(null), + extra_schedules: Joi.array().optional().allow(null), }), }), async (req: Request, res: Response, next: NextFunction) => { @@ -333,6 +334,7 @@ export default (app: Router) => { schedule: Joi.string().required(), name: Joi.string().optional().allow(null), sub_id: Joi.number().optional().allow(null), + extra_schedules: Joi.array().optional().allow(null), id: Joi.number().required(), }), }), diff --git a/back/data/cron.ts b/back/data/cron.ts index ac114402..67a57c95 100644 --- a/back/data/cron.ts +++ b/back/data/cron.ts @@ -18,6 +18,7 @@ export class Crontab { last_running_time?: number; last_execution_time?: number; sub_id?: number; + extra_schedules?: Array<{ schedule: string }>; constructor(options: Crontab) { this.name = options.name; @@ -39,6 +40,7 @@ export class Crontab { this.last_running_time = options.last_running_time || 0; this.last_execution_time = options.last_execution_time || 0; this.sub_id = options.sub_id; + this.extra_schedules = options.extra_schedules; } } @@ -49,7 +51,7 @@ export enum CrontabStatus { 'disabled', } -export interface CronInstance extends Model, Crontab {} +export interface CronInstance extends Model, Crontab { } export const CrontabModel = sequelize.define('Crontab', { name: { unique: 'compositeIndex', @@ -75,4 +77,5 @@ export const CrontabModel = sequelize.define('Crontab', { last_running_time: DataTypes.NUMBER, last_execution_time: DataTypes.NUMBER, sub_id: { type: DataTypes.NUMBER, allowNull: true }, + extra_schedules: DataTypes.JSON }); diff --git a/back/loaders/db.ts b/back/loaders/db.ts index 49f64f90..63a6d500 100644 --- a/back/loaders/db.ts +++ b/back/loaders/db.ts @@ -48,7 +48,10 @@ export default async () => { } catch (error) {} try { await sequelize.query('alter table Crontabs add column sub_id NUMBER'); - } catch (error) {} + } catch (error) { } + try { + await sequelize.query('alter table Crontabs add column extra_schedules JSON'); + } catch (error) { } // 2.10-2.11 升级 const cronDbFile = path.join(config.rootPath, 'db/crontab.db'); diff --git a/back/protos/cron.proto b/back/protos/cron.proto index c1b0be46..b09ba065 100644 --- a/back/protos/cron.proto +++ b/back/protos/cron.proto @@ -7,10 +7,13 @@ service Cron { rpc delCron(DeleteCronRequest) returns (DeleteCronResponse); } +message ISchedule { string schedule = 1; } + message ICron { string id = 1; string schedule = 2; string command = 3; + repeated ISchedule extra_schedules = 4; } message AddCronRequest { repeated ICron crons = 1; } diff --git a/back/protos/cron.ts b/back/protos/cron.ts index cbbc2038..e60f686b 100644 --- a/back/protos/cron.ts +++ b/back/protos/cron.ts @@ -10,78 +10,150 @@ import { Metadata, ServiceError, UntypedServiceImplementation, -} from '@grpc/grpc-js'; -import _m0 from 'protobufjs/minimal'; +} from "@grpc/grpc-js"; +import _m0 from "protobufjs/minimal"; -export const protobufPackage = 'com.ql.cron'; +export const protobufPackage = "com.ql.cron"; + +export interface ISchedule { + schedule: string; +} export interface ICron { id: string; schedule: string; command: string; + extraSchedules: ISchedule[]; } export interface AddCronRequest { crons: ICron[]; } -export interface AddCronResponse {} +export interface AddCronResponse { +} export interface DeleteCronRequest { ids: string[]; } -export interface DeleteCronResponse {} +export interface DeleteCronResponse { +} + +function createBaseISchedule(): ISchedule { + return { schedule: "" }; +} + +export const ISchedule = { + encode(message: ISchedule, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.schedule !== "") { + writer.uint32(10).string(message.schedule); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): ISchedule { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseISchedule(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.schedule = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): ISchedule { + return { schedule: isSet(object.schedule) ? String(object.schedule) : "" }; + }, + + toJSON(message: ISchedule): unknown { + const obj: any = {}; + message.schedule !== undefined && (obj.schedule = message.schedule); + return obj; + }, + + create, I>>(base?: I): ISchedule { + return ISchedule.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): ISchedule { + const message = createBaseISchedule(); + message.schedule = object.schedule ?? ""; + return message; + }, +}; function createBaseICron(): ICron { - return { id: '', schedule: '', command: '' }; + return { id: "", schedule: "", command: "", extraSchedules: [] }; } export const ICron = { encode(message: ICron, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.id !== '') { + if (message.id !== "") { writer.uint32(10).string(message.id); } - if (message.schedule !== '') { + if (message.schedule !== "") { writer.uint32(18).string(message.schedule); } - if (message.command !== '') { + if (message.command !== "") { writer.uint32(26).string(message.command); } + for (const v of message.extraSchedules) { + ISchedule.encode(v!, writer.uint32(34).fork()).ldelim(); + } return writer; }, decode(input: _m0.Reader | Uint8Array, length?: number): ICron { - const reader = - input instanceof _m0.Reader ? input : _m0.Reader.create(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseICron(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: - if (tag != 10) { + if (tag !== 10) { break; } message.id = reader.string(); continue; case 2: - if (tag != 18) { + if (tag !== 18) { break; } message.schedule = reader.string(); continue; case 3: - if (tag != 26) { + if (tag !== 26) { break; } message.command = reader.string(); continue; + case 4: + if (tag !== 34) { + break; + } + + message.extraSchedules.push(ISchedule.decode(reader, reader.uint32())); + continue; } - if ((tag & 7) == 4 || tag == 0) { + if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); @@ -91,9 +163,12 @@ export const ICron = { fromJSON(object: any): ICron { return { - id: isSet(object.id) ? String(object.id) : '', - schedule: isSet(object.schedule) ? String(object.schedule) : '', - command: isSet(object.command) ? String(object.command) : '', + id: isSet(object.id) ? String(object.id) : "", + schedule: isSet(object.schedule) ? String(object.schedule) : "", + command: isSet(object.command) ? String(object.command) : "", + extraSchedules: Array.isArray(object?.extraSchedules) + ? object.extraSchedules.map((e: any) => ISchedule.fromJSON(e)) + : [], }; }, @@ -102,6 +177,11 @@ export const ICron = { message.id !== undefined && (obj.id = message.id); message.schedule !== undefined && (obj.schedule = message.schedule); message.command !== undefined && (obj.command = message.command); + if (message.extraSchedules) { + obj.extraSchedules = message.extraSchedules.map((e) => e ? ISchedule.toJSON(e) : undefined); + } else { + obj.extraSchedules = []; + } return obj; }, @@ -111,9 +191,10 @@ export const ICron = { fromPartial, I>>(object: I): ICron { const message = createBaseICron(); - message.id = object.id ?? ''; - message.schedule = object.schedule ?? ''; - message.command = object.command ?? ''; + message.id = object.id ?? ""; + message.schedule = object.schedule ?? ""; + message.command = object.command ?? ""; + message.extraSchedules = object.extraSchedules?.map((e) => ISchedule.fromPartial(e)) || []; return message; }, }; @@ -123,10 +204,7 @@ function createBaseAddCronRequest(): AddCronRequest { } export const AddCronRequest = { - encode( - message: AddCronRequest, - writer: _m0.Writer = _m0.Writer.create(), - ): _m0.Writer { + encode(message: AddCronRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { for (const v of message.crons) { ICron.encode(v!, writer.uint32(10).fork()).ldelim(); } @@ -134,22 +212,21 @@ export const AddCronRequest = { }, decode(input: _m0.Reader | Uint8Array, length?: number): AddCronRequest { - const reader = - input instanceof _m0.Reader ? input : _m0.Reader.create(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseAddCronRequest(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: - if (tag != 10) { + if (tag !== 10) { break; } message.crons.push(ICron.decode(reader, reader.uint32())); continue; } - if ((tag & 7) == 4 || tag == 0) { + if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); @@ -158,32 +235,24 @@ export const AddCronRequest = { }, fromJSON(object: any): AddCronRequest { - return { - crons: Array.isArray(object?.crons) - ? object.crons.map((e: any) => ICron.fromJSON(e)) - : [], - }; + return { crons: Array.isArray(object?.crons) ? object.crons.map((e: any) => ICron.fromJSON(e)) : [] }; }, toJSON(message: AddCronRequest): unknown { const obj: any = {}; if (message.crons) { - obj.crons = message.crons.map((e) => (e ? ICron.toJSON(e) : undefined)); + obj.crons = message.crons.map((e) => e ? ICron.toJSON(e) : undefined); } else { obj.crons = []; } return obj; }, - create, I>>( - base?: I, - ): AddCronRequest { + create, I>>(base?: I): AddCronRequest { return AddCronRequest.fromPartial(base ?? {}); }, - fromPartial, I>>( - object: I, - ): AddCronRequest { + fromPartial, I>>(object: I): AddCronRequest { const message = createBaseAddCronRequest(); message.crons = object.crons?.map((e) => ICron.fromPartial(e)) || []; return message; @@ -195,23 +264,19 @@ function createBaseAddCronResponse(): AddCronResponse { } export const AddCronResponse = { - encode( - _: AddCronResponse, - writer: _m0.Writer = _m0.Writer.create(), - ): _m0.Writer { + encode(_: AddCronResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { return writer; }, decode(input: _m0.Reader | Uint8Array, length?: number): AddCronResponse { - const reader = - input instanceof _m0.Reader ? input : _m0.Reader.create(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseAddCronResponse(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { } - if ((tag & 7) == 4 || tag == 0) { + if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); @@ -228,15 +293,11 @@ export const AddCronResponse = { return obj; }, - create, I>>( - base?: I, - ): AddCronResponse { + create, I>>(base?: I): AddCronResponse { return AddCronResponse.fromPartial(base ?? {}); }, - fromPartial, I>>( - _: I, - ): AddCronResponse { + fromPartial, I>>(_: I): AddCronResponse { const message = createBaseAddCronResponse(); return message; }, @@ -247,10 +308,7 @@ function createBaseDeleteCronRequest(): DeleteCronRequest { } export const DeleteCronRequest = { - encode( - message: DeleteCronRequest, - writer: _m0.Writer = _m0.Writer.create(), - ): _m0.Writer { + encode(message: DeleteCronRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { for (const v of message.ids) { writer.uint32(10).string(v!); } @@ -258,22 +316,21 @@ export const DeleteCronRequest = { }, decode(input: _m0.Reader | Uint8Array, length?: number): DeleteCronRequest { - const reader = - input instanceof _m0.Reader ? input : _m0.Reader.create(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseDeleteCronRequest(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: - if (tag != 10) { + if (tag !== 10) { break; } message.ids.push(reader.string()); continue; } - if ((tag & 7) == 4 || tag == 0) { + if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); @@ -282,11 +339,7 @@ export const DeleteCronRequest = { }, fromJSON(object: any): DeleteCronRequest { - return { - ids: Array.isArray(object?.ids) - ? object.ids.map((e: any) => String(e)) - : [], - }; + return { ids: Array.isArray(object?.ids) ? object.ids.map((e: any) => String(e)) : [] }; }, toJSON(message: DeleteCronRequest): unknown { @@ -299,15 +352,11 @@ export const DeleteCronRequest = { return obj; }, - create, I>>( - base?: I, - ): DeleteCronRequest { + create, I>>(base?: I): DeleteCronRequest { return DeleteCronRequest.fromPartial(base ?? {}); }, - fromPartial, I>>( - object: I, - ): DeleteCronRequest { + fromPartial, I>>(object: I): DeleteCronRequest { const message = createBaseDeleteCronRequest(); message.ids = object.ids?.map((e) => e) || []; return message; @@ -319,23 +368,19 @@ function createBaseDeleteCronResponse(): DeleteCronResponse { } export const DeleteCronResponse = { - encode( - _: DeleteCronResponse, - writer: _m0.Writer = _m0.Writer.create(), - ): _m0.Writer { + encode(_: DeleteCronResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { return writer; }, decode(input: _m0.Reader | Uint8Array, length?: number): DeleteCronResponse { - const reader = - input instanceof _m0.Reader ? input : _m0.Reader.create(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseDeleteCronResponse(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { } - if ((tag & 7) == 4 || tag == 0) { + if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); @@ -352,15 +397,11 @@ export const DeleteCronResponse = { return obj; }, - create, I>>( - base?: I, - ): DeleteCronResponse { + create, I>>(base?: I): DeleteCronResponse { return DeleteCronResponse.fromPartial(base ?? {}); }, - fromPartial, I>>( - _: I, - ): DeleteCronResponse { + fromPartial, I>>(_: I): DeleteCronResponse { const message = createBaseDeleteCronResponse(); return message; }, @@ -369,25 +410,21 @@ export const DeleteCronResponse = { export type CronService = typeof CronService; export const CronService = { addCron: { - path: '/com.ql.cron.Cron/addCron', + path: "/com.ql.cron.Cron/addCron", requestStream: false, responseStream: false, - requestSerialize: (value: AddCronRequest) => - Buffer.from(AddCronRequest.encode(value).finish()), + requestSerialize: (value: AddCronRequest) => Buffer.from(AddCronRequest.encode(value).finish()), requestDeserialize: (value: Buffer) => AddCronRequest.decode(value), - responseSerialize: (value: AddCronResponse) => - Buffer.from(AddCronResponse.encode(value).finish()), + responseSerialize: (value: AddCronResponse) => Buffer.from(AddCronResponse.encode(value).finish()), responseDeserialize: (value: Buffer) => AddCronResponse.decode(value), }, delCron: { - path: '/com.ql.cron.Cron/delCron', + path: "/com.ql.cron.Cron/delCron", requestStream: false, responseStream: false, - requestSerialize: (value: DeleteCronRequest) => - Buffer.from(DeleteCronRequest.encode(value).finish()), + requestSerialize: (value: DeleteCronRequest) => Buffer.from(DeleteCronRequest.encode(value).finish()), requestDeserialize: (value: Buffer) => DeleteCronRequest.decode(value), - responseSerialize: (value: DeleteCronResponse) => - Buffer.from(DeleteCronResponse.encode(value).finish()), + responseSerialize: (value: DeleteCronResponse) => Buffer.from(DeleteCronResponse.encode(value).finish()), responseDeserialize: (value: Buffer) => DeleteCronResponse.decode(value), }, } as const; @@ -415,67 +452,36 @@ export interface CronClient extends Client { ): ClientUnaryCall; delCron( request: DeleteCronRequest, - callback: ( - error: ServiceError | null, - response: DeleteCronResponse, - ) => void, + callback: (error: ServiceError | null, response: DeleteCronResponse) => void, ): ClientUnaryCall; delCron( request: DeleteCronRequest, metadata: Metadata, - callback: ( - error: ServiceError | null, - response: DeleteCronResponse, - ) => void, + callback: (error: ServiceError | null, response: DeleteCronResponse) => void, ): ClientUnaryCall; delCron( request: DeleteCronRequest, metadata: Metadata, options: Partial, - callback: ( - error: ServiceError | null, - response: DeleteCronResponse, - ) => void, + callback: (error: ServiceError | null, response: DeleteCronResponse) => void, ): ClientUnaryCall; } -export const CronClient = makeGenericClientConstructor( - CronService, - 'com.ql.cron.Cron', -) as unknown as { - new ( - address: string, - credentials: ChannelCredentials, - options?: Partial, - ): CronClient; +export const CronClient = makeGenericClientConstructor(CronService, "com.ql.cron.Cron") as unknown as { + new (address: string, credentials: ChannelCredentials, options?: Partial): CronClient; service: typeof CronService; }; -type Builtin = - | Date - | Function - | Uint8Array - | string - | number - | boolean - | undefined; +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; -export type DeepPartial = T extends Builtin - ? T - : T extends Array - ? Array> - : T extends ReadonlyArray - ? ReadonlyArray> - : T extends {} - ? { [K in keyof T]?: DeepPartial } +export type DeepPartial = T extends Builtin ? T + : T extends Array ? Array> : T extends ReadonlyArray ? ReadonlyArray> + : T extends {} ? { [K in keyof T]?: DeepPartial } : Partial; type KeysOfUnion = T extends T ? keyof T : never; -export type Exact = P extends Builtin - ? P - : P & { [K in keyof P]: Exact } & { - [K in Exclude>]: never; - }; +export type Exact = P extends Builtin ? P + : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; function isSet(value: any): boolean { return value !== null && value !== undefined; diff --git a/back/protos/health.ts b/back/protos/health.ts index b85e020e..9266b2e9 100644 --- a/back/protos/health.ts +++ b/back/protos/health.ts @@ -12,10 +12,10 @@ import { Metadata, ServiceError, UntypedServiceImplementation, -} from '@grpc/grpc-js'; -import _m0 from 'protobufjs/minimal'; +} from "@grpc/grpc-js"; +import _m0 from "protobufjs/minimal"; -export const protobufPackage = 'com.ql.health'; +export const protobufPackage = "com.ql.health"; export interface HealthCheckRequest { service: string; @@ -33,79 +33,71 @@ export enum HealthCheckResponse_ServingStatus { UNRECOGNIZED = -1, } -export function healthCheckResponse_ServingStatusFromJSON( - object: any, -): HealthCheckResponse_ServingStatus { +export function healthCheckResponse_ServingStatusFromJSON(object: any): HealthCheckResponse_ServingStatus { switch (object) { case 0: - case 'UNKNOWN': + case "UNKNOWN": return HealthCheckResponse_ServingStatus.UNKNOWN; case 1: - case 'SERVING': + case "SERVING": return HealthCheckResponse_ServingStatus.SERVING; case 2: - case 'NOT_SERVING': + case "NOT_SERVING": return HealthCheckResponse_ServingStatus.NOT_SERVING; case 3: - case 'SERVICE_UNKNOWN': + case "SERVICE_UNKNOWN": return HealthCheckResponse_ServingStatus.SERVICE_UNKNOWN; case -1: - case 'UNRECOGNIZED': + case "UNRECOGNIZED": default: return HealthCheckResponse_ServingStatus.UNRECOGNIZED; } } -export function healthCheckResponse_ServingStatusToJSON( - object: HealthCheckResponse_ServingStatus, -): string { +export function healthCheckResponse_ServingStatusToJSON(object: HealthCheckResponse_ServingStatus): string { switch (object) { case HealthCheckResponse_ServingStatus.UNKNOWN: - return 'UNKNOWN'; + return "UNKNOWN"; case HealthCheckResponse_ServingStatus.SERVING: - return 'SERVING'; + return "SERVING"; case HealthCheckResponse_ServingStatus.NOT_SERVING: - return 'NOT_SERVING'; + return "NOT_SERVING"; case HealthCheckResponse_ServingStatus.SERVICE_UNKNOWN: - return 'SERVICE_UNKNOWN'; + return "SERVICE_UNKNOWN"; case HealthCheckResponse_ServingStatus.UNRECOGNIZED: default: - return 'UNRECOGNIZED'; + return "UNRECOGNIZED"; } } function createBaseHealthCheckRequest(): HealthCheckRequest { - return { service: '' }; + return { service: "" }; } export const HealthCheckRequest = { - encode( - message: HealthCheckRequest, - writer: _m0.Writer = _m0.Writer.create(), - ): _m0.Writer { - if (message.service !== '') { + encode(message: HealthCheckRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.service !== "") { writer.uint32(10).string(message.service); } return writer; }, decode(input: _m0.Reader | Uint8Array, length?: number): HealthCheckRequest { - const reader = - input instanceof _m0.Reader ? input : _m0.Reader.create(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseHealthCheckRequest(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: - if (tag != 10) { + if (tag !== 10) { break; } message.service = reader.string(); continue; } - if ((tag & 7) == 4 || tag == 0) { + if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); @@ -114,7 +106,7 @@ export const HealthCheckRequest = { }, fromJSON(object: any): HealthCheckRequest { - return { service: isSet(object.service) ? String(object.service) : '' }; + return { service: isSet(object.service) ? String(object.service) : "" }; }, toJSON(message: HealthCheckRequest): unknown { @@ -123,17 +115,13 @@ export const HealthCheckRequest = { return obj; }, - create, I>>( - base?: I, - ): HealthCheckRequest { + create, I>>(base?: I): HealthCheckRequest { return HealthCheckRequest.fromPartial(base ?? {}); }, - fromPartial, I>>( - object: I, - ): HealthCheckRequest { + fromPartial, I>>(object: I): HealthCheckRequest { const message = createBaseHealthCheckRequest(); - message.service = object.service ?? ''; + message.service = object.service ?? ""; return message; }, }; @@ -143,10 +131,7 @@ function createBaseHealthCheckResponse(): HealthCheckResponse { } export const HealthCheckResponse = { - encode( - message: HealthCheckResponse, - writer: _m0.Writer = _m0.Writer.create(), - ): _m0.Writer { + encode(message: HealthCheckResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { if (message.status !== 0) { writer.uint32(8).int32(message.status); } @@ -154,22 +139,21 @@ export const HealthCheckResponse = { }, decode(input: _m0.Reader | Uint8Array, length?: number): HealthCheckResponse { - const reader = - input instanceof _m0.Reader ? input : _m0.Reader.create(input); + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseHealthCheckResponse(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: - if (tag != 8) { + if (tag !== 8) { break; } message.status = reader.int32() as any; continue; } - if ((tag & 7) == 4 || tag == 0) { + if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); @@ -178,29 +162,20 @@ export const HealthCheckResponse = { }, fromJSON(object: any): HealthCheckResponse { - return { - status: isSet(object.status) - ? healthCheckResponse_ServingStatusFromJSON(object.status) - : 0, - }; + return { status: isSet(object.status) ? healthCheckResponse_ServingStatusFromJSON(object.status) : 0 }; }, toJSON(message: HealthCheckResponse): unknown { const obj: any = {}; - message.status !== undefined && - (obj.status = healthCheckResponse_ServingStatusToJSON(message.status)); + message.status !== undefined && (obj.status = healthCheckResponse_ServingStatusToJSON(message.status)); return obj; }, - create, I>>( - base?: I, - ): HealthCheckResponse { + create, I>>(base?: I): HealthCheckResponse { return HealthCheckResponse.fromPartial(base ?? {}); }, - fromPartial, I>>( - object: I, - ): HealthCheckResponse { + fromPartial, I>>(object: I): HealthCheckResponse { const message = createBaseHealthCheckResponse(); message.status = object.status ?? 0; return message; @@ -210,25 +185,21 @@ export const HealthCheckResponse = { export type HealthService = typeof HealthService; export const HealthService = { check: { - path: '/com.ql.health.Health/Check', + path: "/com.ql.health.Health/Check", requestStream: false, responseStream: false, - requestSerialize: (value: HealthCheckRequest) => - Buffer.from(HealthCheckRequest.encode(value).finish()), + requestSerialize: (value: HealthCheckRequest) => Buffer.from(HealthCheckRequest.encode(value).finish()), requestDeserialize: (value: Buffer) => HealthCheckRequest.decode(value), - responseSerialize: (value: HealthCheckResponse) => - Buffer.from(HealthCheckResponse.encode(value).finish()), + responseSerialize: (value: HealthCheckResponse) => Buffer.from(HealthCheckResponse.encode(value).finish()), responseDeserialize: (value: Buffer) => HealthCheckResponse.decode(value), }, watch: { - path: '/com.ql.health.Health/Watch', + path: "/com.ql.health.Health/Watch", requestStream: false, responseStream: true, - requestSerialize: (value: HealthCheckRequest) => - Buffer.from(HealthCheckRequest.encode(value).finish()), + requestSerialize: (value: HealthCheckRequest) => Buffer.from(HealthCheckRequest.encode(value).finish()), requestDeserialize: (value: Buffer) => HealthCheckRequest.decode(value), - responseSerialize: (value: HealthCheckResponse) => - Buffer.from(HealthCheckResponse.encode(value).finish()), + responseSerialize: (value: HealthCheckResponse) => Buffer.from(HealthCheckResponse.encode(value).finish()), responseDeserialize: (value: Buffer) => HealthCheckResponse.decode(value), }, } as const; @@ -241,32 +212,20 @@ export interface HealthServer extends UntypedServiceImplementation { export interface HealthClient extends Client { check( request: HealthCheckRequest, - callback: ( - error: ServiceError | null, - response: HealthCheckResponse, - ) => void, + callback: (error: ServiceError | null, response: HealthCheckResponse) => void, ): ClientUnaryCall; check( request: HealthCheckRequest, metadata: Metadata, - callback: ( - error: ServiceError | null, - response: HealthCheckResponse, - ) => void, + callback: (error: ServiceError | null, response: HealthCheckResponse) => void, ): ClientUnaryCall; check( request: HealthCheckRequest, metadata: Metadata, options: Partial, - callback: ( - error: ServiceError | null, - response: HealthCheckResponse, - ) => void, + callback: (error: ServiceError | null, response: HealthCheckResponse) => void, ): ClientUnaryCall; - watch( - request: HealthCheckRequest, - options?: Partial, - ): ClientReadableStream; + watch(request: HealthCheckRequest, options?: Partial): ClientReadableStream; watch( request: HealthCheckRequest, metadata?: Metadata, @@ -274,43 +233,21 @@ export interface HealthClient extends Client { ): ClientReadableStream; } -export const HealthClient = makeGenericClientConstructor( - HealthService, - 'com.ql.health.Health', -) as unknown as { - new ( - address: string, - credentials: ChannelCredentials, - options?: Partial, - ): HealthClient; +export const HealthClient = makeGenericClientConstructor(HealthService, "com.ql.health.Health") as unknown as { + new (address: string, credentials: ChannelCredentials, options?: Partial): HealthClient; service: typeof HealthService; }; -type Builtin = - | Date - | Function - | Uint8Array - | string - | number - | boolean - | undefined; +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; -export type DeepPartial = T extends Builtin - ? T - : T extends Array - ? Array> - : T extends ReadonlyArray - ? ReadonlyArray> - : T extends {} - ? { [K in keyof T]?: DeepPartial } +export type DeepPartial = T extends Builtin ? T + : T extends Array ? Array> : T extends ReadonlyArray ? ReadonlyArray> + : T extends {} ? { [K in keyof T]?: DeepPartial } : Partial; type KeysOfUnion = T extends T ? keyof T : never; -export type Exact = P extends Builtin - ? P - : P & { [K in keyof P]: Exact } & { - [K in Exclude>]: never; - }; +export type Exact = P extends Builtin ? P + : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; function isSet(value: any): boolean { return value !== null && value !== undefined; diff --git a/back/schedule/addCron.ts b/back/schedule/addCron.ts index d8265199..1b123568 100644 --- a/back/schedule/addCron.ts +++ b/back/schedule/addCron.ts @@ -5,16 +5,15 @@ import { scheduleStacks } from './data'; import { runCron } from '../shared/runCron'; import { QL_PREFIX, TASK_PREFIX } from '../config/const'; import Logger from '../loaders/logger'; -import dayjs from 'dayjs'; const addCron = ( call: ServerUnaryCall, callback: sendUnaryData, ) => { for (const item of call.request.crons) { - const { id, schedule, command } = item; + const { id, schedule, command, extraSchedules } = item; if (scheduleStacks.has(id)) { - scheduleStacks.get(id)?.cancel(); + scheduleStacks.get(id)?.forEach((x) => x.cancel()); } let cmdStr = command.trim(); @@ -29,15 +28,31 @@ const addCron = ( command, ); - scheduleStacks.set( - id, - nodeSchedule.scheduleJob(id, schedule, async () => { + if (extraSchedules?.length) { + extraSchedules.forEach(x => { Logger.info( - `[schedule][准备运行任务] 命令: ${cmdStr}`, + '[schedule][创建定时任务], 任务ID: %s, cron: %s, 执行命令: %s', + id, + x.schedule, + command, ); + }) + } + + scheduleStacks.set(id, [ + nodeSchedule.scheduleJob(id, schedule, async () => { + Logger.info(`[schedule][准备运行任务] 命令: ${cmdStr}`); runCron(`ID=${id} ${cmdStr}`); }), - ); + ...(extraSchedules?.length + ? extraSchedules.map((x) => + nodeSchedule.scheduleJob(id, x.schedule, async () => { + Logger.info(`[schedule][准备运行任务] 命令: ${cmdStr}`); + runCron(`ID=${id} ${cmdStr}`); + }), + ) + : []), + ]); } callback(null, null); diff --git a/back/schedule/data.ts b/back/schedule/data.ts index 113d18f9..3d911529 100644 --- a/back/schedule/data.ts +++ b/back/schedule/data.ts @@ -1,6 +1,6 @@ import nodeSchedule from 'node-schedule'; import { ToadScheduler } from 'toad-scheduler'; -export const scheduleStacks = new Map(); +export const scheduleStacks = new Map(); export const intervalSchedule = new ToadScheduler(); diff --git a/back/schedule/delCron.ts b/back/schedule/delCron.ts index 0608a794..91daee32 100644 --- a/back/schedule/delCron.ts +++ b/back/schedule/delCron.ts @@ -13,7 +13,7 @@ const delCron = ( '[schedule][取消定时任务], 任务ID: %s', id, ); - scheduleStacks.get(id)?.cancel(); + scheduleStacks.get(id)?.forEach(x => x.cancel()); scheduleStacks.delete(id); } } diff --git a/back/services/cron.ts b/back/services/cron.ts index 0e5a175a..9f5ad8d0 100644 --- a/back/services/cron.ts +++ b/back/services/cron.ts @@ -31,9 +31,9 @@ export default class CronService { const tab = new Crontab(payload); tab.saved = false; const doc = await this.insert(tab); - if (this.isSixCron(doc)) { + if (this.isSixCron(doc) || doc.extra_schedules?.length) { await cronClient.addCron([ - { id: String(doc.id), schedule: doc.schedule!, command: doc.command }, + { id: String(doc.id), schedule: doc.schedule!, command: doc.command, extraSchedules: doc.extra_schedules || [] }, ]); } await this.set_crontab(); @@ -52,15 +52,16 @@ export default class CronService { if (doc.isDisabled === 1) { return newDoc; } - if (this.isSixCron(doc)) { + if (this.isSixCron(doc) || doc.extra_schedules?.length) { await cronClient.delCron([String(newDoc.id)]); } - if (this.isSixCron(newDoc)) { + if (this.isSixCron(newDoc) || doc.extra_schedules?.length) { await cronClient.addCron([ { id: String(newDoc.id), schedule: newDoc.schedule!, command: newDoc.command, + extraSchedules: newDoc.extra_schedules || [] }, ]); } @@ -463,6 +464,7 @@ export default class CronService { id: String(doc.id), schedule: doc.schedule!, command: doc.command, + extraSchedules: doc.extra_schedules || [] })); await cronClient.addCron(sixCron); await this.set_crontab(); @@ -519,7 +521,7 @@ export default class CronService { var crontab_string = ''; tabs.data.forEach((tab) => { const _schedule = tab.schedule && tab.schedule.split(/ +/); - if (tab.isDisabled === 1 || _schedule!.length !== 5) { + if (tab.isDisabled === 1 || _schedule!.length !== 5 || tab.extra_schedules?.length) { crontab_string += '# '; crontab_string += tab.schedule; crontab_string += ' '; @@ -583,6 +585,7 @@ export default class CronService { id: String(doc.id), schedule: doc.schedule!, command: doc.command, + extraSchedules: doc.extra_schedules || [] })); await cronClient.addCron(sixCron); } diff --git a/src/layouts/index.less b/src/layouts/index.less index 3bc7a6be..06b86b80 100644 --- a/src/layouts/index.less +++ b/src/layouts/index.less @@ -451,3 +451,9 @@ body[data-mode='phone'] header { .ant-table.ant-table-middle tfoot > tr > td { padding: 12px 16px; } + +body[data-dark='true'] { + .ant-popover-arrow-content { + --antd-arrow-background-color: rgb(24, 26, 27); + } +} diff --git a/src/locales/en-US.json b/src/locales/en-US.json index dfef43dc..f19a672c 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -453,5 +453,6 @@ "主题": "Theme", "语言": "Language", "中...": "ing...", - "请选择操作符": "Please select operator" + "请选择操作符": "Please select operator", + "新增定时规则": "New Timing Rules" } diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index fe0330e9..a6ca3bee 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -453,5 +453,6 @@ "主题": "主题", "语言": "语言", "中...": "中...", - "请选择操作符": "请选择操作符" + "请选择操作符": "请选择操作符", + "新增定时规则": "新增定时规则" } diff --git a/src/pages/crontab/index.tsx b/src/pages/crontab/index.tsx index 6353cb8c..de3310cd 100644 --- a/src/pages/crontab/index.tsx +++ b/src/pages/crontab/index.tsx @@ -183,6 +183,20 @@ const Crontab = () => { sorter: { compare: (a, b) => a.schedule.localeCompare(b.schedule), }, + render: (text, record) => { + return record.extra_schedules?.length ? ( + ( +
{x.schedule}
+ ))} + > + {text} +
+ ) : ( + text + ); + }, }, { title: intl.get('最后运行时长'), diff --git a/src/pages/crontab/modal.tsx b/src/pages/crontab/modal.tsx index dfba1484..1bee2419 100644 --- a/src/pages/crontab/modal.tsx +++ b/src/pages/crontab/modal.tsx @@ -1,10 +1,11 @@ import intl from 'react-intl-universal'; import React, { useEffect, useState } from 'react'; -import { Modal, message, Input, Form, Button } from 'antd'; +import { Modal, message, Input, Form, Button, Space } from 'antd'; import { request } from '@/utils/http'; import config from '@/utils/config'; import cronParse from 'cron-parser'; import EditableTagGroup from '@/components/tag'; +import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; const CronModal = ({ cron, @@ -107,6 +108,38 @@ const CronModal = ({ > + + {(fields, { add, remove }, { errors }) => ( + <> + {fields.map(({ key, name, ...restField }) => ( + + + + + + remove(name)} + /> + + + ))} + + add({ schedule: '' })}> + + {intl.get('新增定时规则')} + + + + + )} + diff --git a/src/pages/crontab/type.ts b/src/pages/crontab/type.ts index 9be2d2ed..dcb6459e 100644 --- a/src/pages/crontab/type.ts +++ b/src/pages/crontab/type.ts @@ -35,4 +35,6 @@ export interface ICrontab { last_running_time?: number; last_execution_time?: number; nextRunTime: Date; + sub_id: number; + extra_schedules?: Array<{ schedule: string; }>; } diff --git a/src/pages/crontab/viewCreateModal.tsx b/src/pages/crontab/viewCreateModal.tsx index ef261091..2e00b88e 100644 --- a/src/pages/crontab/viewCreateModal.tsx +++ b/src/pages/crontab/viewCreateModal.tsx @@ -195,7 +195,7 @@ const ViewCreateModal = ({ - {(fields, { add, remove }) => ( + {(fields, { add, remove }, { errors }) => (
+
)}
- {(fields, { add, remove }) => ( + {(fields, { add, remove }, { errors }) => (
+
)}