mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-14 01:34:47 +08:00
feat: 计划任务增加每隔 n 秒执行 (#1132)
This commit is contained in:
parent
93b03c7212
commit
f65f0d86aa
@ -10,6 +10,7 @@ type CronjobCreate struct {
|
|||||||
Day int `json:"day" validate:"number"`
|
Day int `json:"day" validate:"number"`
|
||||||
Hour int `json:"hour" validate:"number"`
|
Hour int `json:"hour" validate:"number"`
|
||||||
Minute int `json:"minute" validate:"number"`
|
Minute int `json:"minute" validate:"number"`
|
||||||
|
Second int `json:"second" validate:"number"`
|
||||||
|
|
||||||
Script string `json:"script"`
|
Script string `json:"script"`
|
||||||
Website string `json:"website"`
|
Website string `json:"website"`
|
||||||
@ -30,6 +31,7 @@ type CronjobUpdate struct {
|
|||||||
Day int `json:"day" validate:"number"`
|
Day int `json:"day" validate:"number"`
|
||||||
Hour int `json:"hour" validate:"number"`
|
Hour int `json:"hour" validate:"number"`
|
||||||
Minute int `json:"minute" validate:"number"`
|
Minute int `json:"minute" validate:"number"`
|
||||||
|
Second int `json:"second" validate:"number"`
|
||||||
|
|
||||||
Script string `json:"script"`
|
Script string `json:"script"`
|
||||||
Website string `json:"website"`
|
Website string `json:"website"`
|
||||||
@ -71,6 +73,7 @@ type CronjobInfo struct {
|
|||||||
Day int `json:"day"`
|
Day int `json:"day"`
|
||||||
Hour int `json:"hour"`
|
Hour int `json:"hour"`
|
||||||
Minute int `json:"minute"`
|
Minute int `json:"minute"`
|
||||||
|
Second int `json:"second"`
|
||||||
|
|
||||||
Script string `json:"script"`
|
Script string `json:"script"`
|
||||||
Website string `json:"website"`
|
Website string `json:"website"`
|
||||||
|
@ -13,6 +13,7 @@ type Cronjob struct {
|
|||||||
Day uint64 `gorm:"type:decimal" json:"day"`
|
Day uint64 `gorm:"type:decimal" json:"day"`
|
||||||
Hour uint64 `gorm:"type:decimal" json:"hour"`
|
Hour uint64 `gorm:"type:decimal" json:"hour"`
|
||||||
Minute uint64 `gorm:"type:decimal" json:"minute"`
|
Minute uint64 `gorm:"type:decimal" json:"minute"`
|
||||||
|
Second uint64 `gorm:"type:decimal" json:"second"`
|
||||||
|
|
||||||
Script string `gorm:"longtext" json:"script"`
|
Script string `gorm:"longtext" json:"script"`
|
||||||
Website string `gorm:"type:varchar(64)" json:"website"`
|
Website string `gorm:"type:varchar(64)" json:"website"`
|
||||||
|
@ -322,6 +322,8 @@ func loadSpec(cronjob model.Cronjob) string {
|
|||||||
return fmt.Sprintf("%v * * * *", cronjob.Minute)
|
return fmt.Sprintf("%v * * * *", cronjob.Minute)
|
||||||
case "perNMinute":
|
case "perNMinute":
|
||||||
return fmt.Sprintf("@every %vm", cronjob.Minute)
|
return fmt.Sprintf("@every %vm", cronjob.Minute)
|
||||||
|
case "perNSecond":
|
||||||
|
return fmt.Sprintf("@every %vs", cronjob.Second)
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ func Init() {
|
|||||||
migrations.UpdateTableSetting,
|
migrations.UpdateTableSetting,
|
||||||
migrations.UpdateTableAppDetail,
|
migrations.UpdateTableAppDetail,
|
||||||
migrations.AddBindAndAllowIPs,
|
migrations.AddBindAndAllowIPs,
|
||||||
|
migrations.UpdateCronjobWithSecond,
|
||||||
})
|
})
|
||||||
if err := m.Migrate(); err != nil {
|
if err := m.Migrate(); err != nil {
|
||||||
global.LOG.Error(err)
|
global.LOG.Error(err)
|
||||||
|
@ -337,7 +337,7 @@ var UpdateTableAppDetail = &gormigrate.Migration{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var AddBindAndAllowIPs = &gormigrate.Migration{
|
var AddBindAndAllowIPs = &gormigrate.Migration{
|
||||||
ID: "20230414-add-bind-and-allow",
|
ID: "20230517-add-bind-and-allow",
|
||||||
Migrate: func(tx *gorm.DB) error {
|
Migrate: func(tx *gorm.DB) error {
|
||||||
if err := tx.Create(&model.Setting{Key: "BindDomain", Value: ""}).Error; err != nil {
|
if err := tx.Create(&model.Setting{Key: "BindDomain", Value: ""}).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
@ -354,3 +354,13 @@ var AddBindAndAllowIPs = &gormigrate.Migration{
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var UpdateCronjobWithSecond = &gormigrate.Migration{
|
||||||
|
ID: "20200524-update-table-cronjob",
|
||||||
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
if err := tx.AutoMigrate(&model.Cronjob{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -10,6 +10,7 @@ export namespace Cronjob {
|
|||||||
day: number;
|
day: number;
|
||||||
hour: number;
|
hour: number;
|
||||||
minute: number;
|
minute: number;
|
||||||
|
second: number;
|
||||||
|
|
||||||
script: string;
|
script: string;
|
||||||
website: string;
|
website: string;
|
||||||
@ -31,6 +32,7 @@ export namespace Cronjob {
|
|||||||
day: number;
|
day: number;
|
||||||
hour: number;
|
hour: number;
|
||||||
minute: number;
|
minute: number;
|
||||||
|
second: number;
|
||||||
|
|
||||||
script: string;
|
script: string;
|
||||||
website: string;
|
website: string;
|
||||||
@ -49,6 +51,7 @@ export namespace Cronjob {
|
|||||||
day: number;
|
day: number;
|
||||||
hour: number;
|
hour: number;
|
||||||
minute: number;
|
minute: number;
|
||||||
|
second: number;
|
||||||
|
|
||||||
script: string;
|
script: string;
|
||||||
website: string;
|
website: string;
|
||||||
|
@ -651,12 +651,14 @@ const message = {
|
|||||||
perDay: 'Every days',
|
perDay: 'Every days',
|
||||||
perNHour: 'Every N hours',
|
perNHour: 'Every N hours',
|
||||||
perNMinute: 'Every N minutes',
|
perNMinute: 'Every N minutes',
|
||||||
|
perNSecond: 'Every N seconds',
|
||||||
per: 'Every ',
|
per: 'Every ',
|
||||||
handle: 'Handle',
|
handle: 'Handle',
|
||||||
day: 'Day',
|
day: 'Day',
|
||||||
day1: 'Day',
|
day1: 'Day',
|
||||||
hour: ' Hour',
|
hour: ' Hour',
|
||||||
minute: ' Minute',
|
minute: ' Minute',
|
||||||
|
second: ' Second',
|
||||||
monday: 'Monday',
|
monday: 'Monday',
|
||||||
tuesday: 'Tuesday',
|
tuesday: 'Tuesday',
|
||||||
wednesday: 'Wednesday',
|
wednesday: 'Wednesday',
|
||||||
|
@ -657,12 +657,14 @@ const message = {
|
|||||||
perDay: '每天',
|
perDay: '每天',
|
||||||
perNHour: '每隔 N 时',
|
perNHour: '每隔 N 时',
|
||||||
perNMinute: '每隔 N 分钟',
|
perNMinute: '每隔 N 分钟',
|
||||||
|
perNSecond: '每隔 N 秒',
|
||||||
per: '每隔',
|
per: '每隔',
|
||||||
handle: '执行',
|
handle: '执行',
|
||||||
day: '日',
|
day: '日',
|
||||||
day1: '天',
|
day1: '天',
|
||||||
hour: '小时',
|
hour: '小时',
|
||||||
minute: '分钟',
|
minute: '分钟',
|
||||||
|
second: '秒',
|
||||||
monday: '周一',
|
monday: '周一',
|
||||||
tuesday: '周二',
|
tuesday: '周二',
|
||||||
wednesday: '周三',
|
wednesday: '周三',
|
||||||
|
@ -95,6 +95,7 @@
|
|||||||
</span>
|
</span>
|
||||||
<span v-if="row.specType === 'perHour'">{{ loadZero(row.minute) }}</span>
|
<span v-if="row.specType === 'perHour'">{{ loadZero(row.minute) }}</span>
|
||||||
<span v-if="row.specType === 'perNMinute'">{{ row.minute }}{{ $t('cronjob.minute') }}</span>
|
<span v-if="row.specType === 'perNMinute'">{{ row.minute }}{{ $t('cronjob.minute') }}</span>
|
||||||
|
<span v-if="row.specType === 'perNSecond'">{{ row.second }}{{ $t('cronjob.second') }}</span>
|
||||||
{{ $t('cronjob.handle') }}
|
{{ $t('cronjob.handle') }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -227,6 +228,7 @@ const onOpenDialog = async (
|
|||||||
day: 3,
|
day: 3,
|
||||||
hour: 1,
|
hour: 1,
|
||||||
minute: 30,
|
minute: 30,
|
||||||
|
second: 30,
|
||||||
keepLocal: true,
|
keepLocal: true,
|
||||||
retainCopies: 7,
|
retainCopies: 7,
|
||||||
},
|
},
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<el-form-item :label="$t('cronjob.taskType')" prop="type">
|
<el-form-item :label="$t('cronjob.taskType')" prop="type">
|
||||||
<el-select
|
<el-select
|
||||||
v-if="dialogData.title === 'create'"
|
v-if="dialogData.title === 'create'"
|
||||||
style="width: 100%"
|
class="selectClass"
|
||||||
@change="changeType"
|
@change="changeType"
|
||||||
v-model="dialogData.rowData!.type"
|
v-model="dialogData.rowData!.type"
|
||||||
>
|
>
|
||||||
@ -27,7 +27,6 @@
|
|||||||
<el-form-item :label="$t('cronjob.taskName')" prop="name">
|
<el-form-item :label="$t('cronjob.taskName')" prop="name">
|
||||||
<el-input
|
<el-input
|
||||||
:disabled="dialogData.title === 'edit'"
|
:disabled="dialogData.title === 'edit'"
|
||||||
style="width: 100%"
|
|
||||||
clearable
|
clearable
|
||||||
v-model.trim="dialogData.rowData!.name"
|
v-model.trim="dialogData.rowData!.name"
|
||||||
/>
|
/>
|
||||||
@ -44,7 +43,7 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
<el-select
|
<el-select
|
||||||
v-if="dialogData.rowData!.specType === 'perWeek'"
|
v-if="dialogData.rowData!.specType === 'perWeek'"
|
||||||
style="width: 12%; margin-left: 20px"
|
class="specClass"
|
||||||
v-model="dialogData.rowData!.week"
|
v-model="dialogData.rowData!.week"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
@ -54,28 +53,30 @@
|
|||||||
:label="item.label"
|
:label="item.label"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-input
|
<el-input v-if="hasDay()" class="specClass" v-model.number="dialogData.rowData!.day">
|
||||||
v-if="dialogData.rowData!.specType === 'perMonth' || dialogData.rowData!.specType === 'perNDay'"
|
|
||||||
style="width: 20%; margin-left: 20px"
|
|
||||||
v-model.number="dialogData.rowData!.day"
|
|
||||||
>
|
|
||||||
<template #append>{{ $t('cronjob.day') }}</template>
|
<template #append>{{ $t('cronjob.day') }}</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
<el-input
|
<el-input v-if="hasHour()" class="specClass" v-model.number="dialogData.rowData!.hour">
|
||||||
v-if="dialogData.rowData!.specType !== 'perHour' && dialogData.rowData!.specType !== 'perNMinute'"
|
|
||||||
style="width: 20%; margin-left: 20px"
|
|
||||||
v-model.number="dialogData.rowData!.hour"
|
|
||||||
>
|
|
||||||
<template #append>{{ $t('cronjob.hour') }}</template>
|
<template #append>{{ $t('cronjob.hour') }}</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
<el-input style="width: 20%; margin-left: 20px" v-model.number="dialogData.rowData!.minute">
|
<el-input
|
||||||
|
v-if="dialogData.rowData!.specType !== 'perNSecond'"
|
||||||
|
class="specClass"
|
||||||
|
v-model.number="dialogData.rowData!.minute"
|
||||||
|
>
|
||||||
<template #append>{{ $t('cronjob.minute') }}</template>
|
<template #append>{{ $t('cronjob.minute') }}</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
|
<el-input
|
||||||
|
v-if="dialogData.rowData!.specType === 'perNSecond'"
|
||||||
|
class="specClass"
|
||||||
|
v-model.number="dialogData.rowData!.second"
|
||||||
|
>
|
||||||
|
<template #append>{{ $t('cronjob.second') }}</template>
|
||||||
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item v-if="hasScript()" :label="$t('cronjob.shellContent')" prop="script">
|
<el-form-item v-if="hasScript()" :label="$t('cronjob.shellContent')" prop="script">
|
||||||
<el-input
|
<el-input
|
||||||
style="width: 100%"
|
|
||||||
clearable
|
clearable
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:autosize="{ minRows: 3, maxRows: 6 }"
|
:autosize="{ minRows: 3, maxRows: 6 }"
|
||||||
@ -88,7 +89,7 @@
|
|||||||
:label="dialogData.rowData!.type === 'website' ? $t('cronjob.website'):$t('website.website')"
|
:label="dialogData.rowData!.type === 'website' ? $t('cronjob.website'):$t('website.website')"
|
||||||
prop="website"
|
prop="website"
|
||||||
>
|
>
|
||||||
<el-select style="width: 100%" v-model="dialogData.rowData!.website">
|
<el-select class="selectClass" v-model="dialogData.rowData!.website">
|
||||||
<el-option :label="$t('commons.table.all')" value="all" />
|
<el-option :label="$t('commons.table.all')" value="all" />
|
||||||
<el-option v-for="item in websiteOptions" :key="item" :value="item" :label="item" />
|
<el-option v-for="item in websiteOptions" :key="item" :value="item" :label="item" />
|
||||||
</el-select>
|
</el-select>
|
||||||
@ -99,7 +100,7 @@
|
|||||||
|
|
||||||
<div v-if="dialogData.rowData!.type === 'database'">
|
<div v-if="dialogData.rowData!.type === 'database'">
|
||||||
<el-form-item :label="$t('cronjob.database')" prop="dbName">
|
<el-form-item :label="$t('cronjob.database')" prop="dbName">
|
||||||
<el-select style="width: 100%" clearable v-model="dialogData.rowData!.dbName">
|
<el-select class="selectClass" clearable v-model="dialogData.rowData!.dbName">
|
||||||
<el-option :label="$t('commons.table.all')" value="all" />
|
<el-option :label="$t('commons.table.all')" value="all" />
|
||||||
<el-option v-for="item in mysqlInfo.dbNames" :key="item" :label="item" :value="item" />
|
<el-option v-for="item in mysqlInfo.dbNames" :key="item" :label="item" :value="item" />
|
||||||
</el-select>
|
</el-select>
|
||||||
@ -111,7 +112,7 @@
|
|||||||
:label="$t('cronjob.sourceDir')"
|
:label="$t('cronjob.sourceDir')"
|
||||||
prop="sourceDir"
|
prop="sourceDir"
|
||||||
>
|
>
|
||||||
<el-input style="width: 100%" v-model="dialogData.rowData!.sourceDir">
|
<el-input v-model="dialogData.rowData!.sourceDir">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<FileList @choose="loadDir" :dir="true"></FileList>
|
<FileList @choose="loadDir" :dir="true"></FileList>
|
||||||
</template>
|
</template>
|
||||||
@ -120,7 +121,7 @@
|
|||||||
|
|
||||||
<div v-if="isBackup()">
|
<div v-if="isBackup()">
|
||||||
<el-form-item :label="$t('cronjob.target')" prop="targetDirID">
|
<el-form-item :label="$t('cronjob.target')" prop="targetDirID">
|
||||||
<el-select style="width: 100%" v-model="dialogData.rowData!.targetDirID">
|
<el-select class="selectClass" v-model="dialogData.rowData!.targetDirID">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in backupOptions"
|
v-for="item in backupOptions"
|
||||||
:key="item.label"
|
:key="item.label"
|
||||||
@ -148,7 +149,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item v-if="dialogData.rowData!.type === 'curl'" :label="$t('cronjob.url')" prop="url">
|
<el-form-item v-if="dialogData.rowData!.type === 'curl'" :label="$t('cronjob.url')" prop="url">
|
||||||
<el-input style="width: 100%" clearable v-model.trim="dialogData.rowData!.url" />
|
<el-input clearable v-model.trim="dialogData.rowData!.url" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item
|
<el-form-item
|
||||||
@ -157,7 +158,6 @@
|
|||||||
prop="exclusionRules"
|
prop="exclusionRules"
|
||||||
>
|
>
|
||||||
<el-input
|
<el-input
|
||||||
style="width: 100%"
|
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:placeholder="$t('cronjob.rulesHelper')"
|
:placeholder="$t('cronjob.rulesHelper')"
|
||||||
:autosize="{ minRows: 3, maxRows: 6 }"
|
:autosize="{ minRows: 3, maxRows: 6 }"
|
||||||
@ -284,6 +284,11 @@ const varifySpec = (rule: any, value: any, callback: any) => {
|
|||||||
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'perNSecond':
|
||||||
|
if (!Number.isInteger(dialogData.value.rowData!.second)) {
|
||||||
|
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
callback();
|
callback();
|
||||||
};
|
};
|
||||||
@ -296,6 +301,7 @@ const specOptions = [
|
|||||||
{ label: i18n.global.t('cronjob.perNDay'), value: 'perNDay' },
|
{ label: i18n.global.t('cronjob.perNDay'), value: 'perNDay' },
|
||||||
{ label: i18n.global.t('cronjob.perNHour'), value: 'perNHour' },
|
{ label: i18n.global.t('cronjob.perNHour'), value: 'perNHour' },
|
||||||
{ label: i18n.global.t('cronjob.perNMinute'), value: 'perNMinute' },
|
{ label: i18n.global.t('cronjob.perNMinute'), value: 'perNMinute' },
|
||||||
|
{ label: i18n.global.t('cronjob.perNSecond'), value: 'perNSecond' },
|
||||||
];
|
];
|
||||||
const weekOptions = [
|
const weekOptions = [
|
||||||
{ label: i18n.global.t('cronjob.monday'), value: 1 },
|
{ label: i18n.global.t('cronjob.monday'), value: 1 },
|
||||||
@ -335,6 +341,17 @@ const loadDir = async (path: string) => {
|
|||||||
dialogData.value.rowData!.sourceDir = path;
|
dialogData.value.rowData!.sourceDir = path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const hasDay = () => {
|
||||||
|
return dialogData.value.rowData!.specType === 'perMonth' || dialogData.value.rowData!.specType === 'perNDay';
|
||||||
|
};
|
||||||
|
const hasHour = () => {
|
||||||
|
return (
|
||||||
|
dialogData.value.rowData!.specType !== 'perHour' &&
|
||||||
|
dialogData.value.rowData!.specType !== 'perNMinute' &&
|
||||||
|
dialogData.value.rowData!.specType !== 'perNSecond'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const changeType = () => {
|
const changeType = () => {
|
||||||
switch (dialogData.value.rowData!.type) {
|
switch (dialogData.value.rowData!.type) {
|
||||||
case 'shell':
|
case 'shell':
|
||||||
@ -430,6 +447,8 @@ function checkScript() {
|
|||||||
return row.hour > 0 && row.hour < 8784 && row.minute >= 0 && row.minute < 60;
|
return row.hour > 0 && row.hour < 8784 && row.minute >= 0 && row.minute < 60;
|
||||||
case 'perNMinute':
|
case 'perNMinute':
|
||||||
return row.minute > 0 && row.minute < 527040;
|
return row.minute > 0 && row.minute < 527040;
|
||||||
|
case 'perNSecond':
|
||||||
|
return row.second > 0 && row.second < 31622400;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,6 +457,7 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
|
|||||||
dialogData.value.rowData.day = Number(dialogData.value.rowData.day);
|
dialogData.value.rowData.day = Number(dialogData.value.rowData.day);
|
||||||
dialogData.value.rowData.hour = Number(dialogData.value.rowData.hour);
|
dialogData.value.rowData.hour = Number(dialogData.value.rowData.hour);
|
||||||
dialogData.value.rowData.minute = Number(dialogData.value.rowData.minute);
|
dialogData.value.rowData.minute = Number(dialogData.value.rowData.minute);
|
||||||
|
dialogData.value.rowData.second = Number(dialogData.value.rowData.second);
|
||||||
if (!checkScript()) {
|
if (!checkScript()) {
|
||||||
MsgError(i18n.global.t('cronjob.cronSpecHelper'));
|
MsgError(i18n.global.t('cronjob.cronSpecHelper'));
|
||||||
return;
|
return;
|
||||||
@ -463,3 +483,12 @@ defineExpose({
|
|||||||
acceptParams,
|
acceptParams,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.specClass {
|
||||||
|
width: 20%;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
.selectClass {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user