mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-18 22:22:59 +08:00
feat: 计划任务支持自定义日志保留份数 (#548)
This commit is contained in:
parent
24246da71c
commit
18b4c98daa
@ -80,21 +80,15 @@ func (u *CronjobService) SearchRecords(search dto.SearchRecord) (int64, interfac
|
||||
}
|
||||
|
||||
func (u *CronjobService) CleanRecord(id uint) error {
|
||||
_, records, err := cronjobRepo.PageRecords(1, 7, cronjobRepo.WithByJobID(int(id)), commonRepo.WithOrderBy("created_at desc"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(records) < 7 {
|
||||
return nil
|
||||
}
|
||||
delRecords, err := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(id)), cronjobRepo.WithByRecordDropID(int(records[6].ID)))
|
||||
delRecords, err := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(id)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, del := range delRecords {
|
||||
_ = os.RemoveAll(del.File)
|
||||
_ = os.RemoveAll(del.Records)
|
||||
}
|
||||
if err := cronjobRepo.DeleteRecord(cronjobRepo.WithByJobID(int(id)), cronjobRepo.WithByRecordDropID(int(records[6].ID))); err != nil {
|
||||
if err := cronjobRepo.DeleteRecord(cronjobRepo.WithByJobID(int(id))); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -1,7 +1,6 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
@ -23,6 +22,7 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||
err error
|
||||
)
|
||||
record := cronjobRepo.StartRecords(cronjob.ID, cronjob.KeepLocal, "")
|
||||
logDir := fmt.Sprintf("%s/1panel/task/%s/%s", global.CONF.System.BaseDir, cronjob.Type, cronjob.Name)
|
||||
go func() {
|
||||
switch cronjob.Type {
|
||||
case "shell":
|
||||
@ -34,6 +34,7 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||
err = errExec
|
||||
}
|
||||
message = []byte(stdout)
|
||||
u.HandleRmExpired("LOCAL", logDir, cronjob, nil)
|
||||
case "website":
|
||||
record.File, err = u.HandleBackup(cronjob, record.StartTime)
|
||||
case "database":
|
||||
@ -52,6 +53,7 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||
err = errCurl
|
||||
}
|
||||
message = []byte(stdout)
|
||||
u.HandleRmExpired("LOCAL", logDir, cronjob, nil)
|
||||
}
|
||||
if err != nil {
|
||||
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), string(message))
|
||||
@ -169,39 +171,13 @@ func (u *CronjobService) HandleRmExpired(backType, backupDir string, cronjob *mo
|
||||
}
|
||||
return
|
||||
}
|
||||
files, err := os.ReadDir(backupDir)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("read dir %s failed, err: %v", backupDir, err)
|
||||
return
|
||||
}
|
||||
if len(files) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
prefix := ""
|
||||
switch cronjob.Type {
|
||||
case "database":
|
||||
prefix = "db_"
|
||||
case "website":
|
||||
prefix = "website_"
|
||||
case "directory":
|
||||
prefix = "directory_"
|
||||
}
|
||||
|
||||
dbCopies := uint64(0)
|
||||
for i := len(files) - 1; i >= 0; i-- {
|
||||
if strings.HasPrefix(files[i].Name(), prefix) {
|
||||
dbCopies++
|
||||
if dbCopies > cronjob.RetainCopies {
|
||||
_ = os.Remove(backupDir + "/" + files[i].Name())
|
||||
_ = backupRepo.DeleteRecord(context.Background(), backupRepo.WithByFileName(files[i].Name()))
|
||||
}
|
||||
}
|
||||
}
|
||||
records, _ := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(cronjob.ID)))
|
||||
records, _ := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(cronjob.ID)), commonRepo.WithOrderBy("created_at desc"))
|
||||
if len(records) > int(cronjob.RetainCopies) {
|
||||
for i := int(cronjob.RetainCopies); i < len(records); i++ {
|
||||
_ = cronjobRepo.DeleteRecord(cronjobRepo.WithByJobID(int(records[i].ID)))
|
||||
_ = cronjobRepo.DeleteRecord(commonRepo.WithByID(uint(records[i].ID)))
|
||||
_ = os.Remove(records[i].File)
|
||||
_ = os.Remove(records[i].Records)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -292,7 +268,8 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, app *repo.RootInf
|
||||
record.Source = backup.Type
|
||||
record.FileDir = itemFileDir
|
||||
}
|
||||
if err := saveBackupRecord(record); err != nil {
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
if backup.Type == "LOCAL" {
|
||||
@ -356,7 +333,8 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, backup model.Backu
|
||||
return err
|
||||
}
|
||||
record.Name = website.PrimaryDomain
|
||||
if err := saveBackupRecord(record); err != nil {
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
if backup.Type == "LOCAL" {
|
||||
@ -382,11 +360,3 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, backup model.Backu
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func saveBackupRecord(record model.BackupRecord) error {
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -585,7 +585,7 @@ const message = {
|
||||
cronSpec: 'Lifecycle',
|
||||
cronSpecHelper: 'Enter the correct execution period',
|
||||
cleanHelper:
|
||||
'This operation will retain the latest seven task execution records and log files. Do you want to continue?',
|
||||
'This operation records all job execution records, backup files, and log files. Do you want to continue?',
|
||||
directory: 'Backup directory',
|
||||
sourceDir: 'Backup directory',
|
||||
allOptionHelper:
|
||||
@ -595,6 +595,7 @@ const message = {
|
||||
url: 'URL Address',
|
||||
target: 'Target',
|
||||
retainCopies: 'Retain copies',
|
||||
retainCopiesHelper: 'Number of copies of execution records, log files, and backup files',
|
||||
cronSpecRule: 'Please enter a correct lifecycle',
|
||||
perMonth: 'Every monthly',
|
||||
perWeek: 'Every week',
|
||||
|
@ -588,7 +588,7 @@ const message = {
|
||||
taskName: '任务名称',
|
||||
cronSpec: '执行周期',
|
||||
cronSpecHelper: '请输入正确的执行周期',
|
||||
cleanHelper: '该操作将保留最新的 7 份任务执行记录和日志文件,是否继续?',
|
||||
cleanHelper: '该操作将所有任务执行记录、备份文件和日志文件,是否继续?',
|
||||
directory: '备份目录',
|
||||
sourceDir: '备份目录',
|
||||
allOptionHelper: '当前计划任务为备份所有 {0},暂不支持直接下载,可在 {0} 备份列表中查看',
|
||||
@ -597,6 +597,7 @@ const message = {
|
||||
url: 'URL 地址',
|
||||
target: '备份到',
|
||||
retainCopies: '保留份数',
|
||||
retainCopiesHelper: '执行记录、日志文件、备份文件保留份数',
|
||||
cronSpecRule: '请输入正确的执行周期',
|
||||
perMonth: '每月',
|
||||
perWeek: '每周',
|
||||
|
@ -91,11 +91,7 @@
|
||||
{{ $t('cronjob.handle') }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('cronjob.retainCopies')" :min-width="90" prop="retainCopies">
|
||||
<template #default="{ row }">
|
||||
{{ loadCopies(row) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('cronjob.retainCopies')" :min-width="90" prop="retainCopies" />
|
||||
|
||||
<el-table-column :label="$t('cronjob.lastRecrodTime')" :min-width="120" prop="lastRecrodTime">
|
||||
<template #default="{ row }">
|
||||
@ -246,14 +242,6 @@ const onHandle = async (row: Cronjob.CronjobInfo) => {
|
||||
});
|
||||
};
|
||||
|
||||
const loadCopies = (item) => {
|
||||
if (item.type === 'shell' || item.type === 'curl') {
|
||||
return '-';
|
||||
} else {
|
||||
return item.retainCopies + '';
|
||||
}
|
||||
};
|
||||
|
||||
const loadDetail = (row: any) => {
|
||||
isRecordShow.value = true;
|
||||
let params = {
|
||||
|
@ -129,17 +129,19 @@
|
||||
{{ $t('cronjob.saveLocal') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('cronjob.retainCopies')" prop="retainCopies">
|
||||
<el-input-number
|
||||
:min="1"
|
||||
:max="30"
|
||||
step-strictly
|
||||
:step="1"
|
||||
v-model.number="dialogData.rowData!.retainCopies"
|
||||
></el-input-number>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<el-form-item :label="$t('cronjob.retainCopies')" prop="retainCopies">
|
||||
<el-input-number
|
||||
:min="1"
|
||||
:max="300"
|
||||
step-strictly
|
||||
:step="1"
|
||||
v-model.number="dialogData.rowData!.retainCopies"
|
||||
></el-input-number>
|
||||
<span class="input-help">{{ $t('cronjob.retainCopiesHelper') }}</span>
|
||||
</el-form-item>
|
||||
|
||||
<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-form-item>
|
||||
|
@ -70,7 +70,7 @@
|
||||
>
|
||||
{{ $t('commons.button.enable') }}
|
||||
</el-button>
|
||||
<el-button type="primary" :disabled="records.length <= 7" @click="cleanRecord()" link>
|
||||
<el-button type="primary" @click="cleanRecord()" link>
|
||||
{{ $t('commons.button.clean') }}
|
||||
</el-button>
|
||||
</span>
|
||||
@ -130,7 +130,7 @@
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<el-form label-position="top">
|
||||
<el-form label-position="top" :v-key="refresh">
|
||||
<el-row type="flex" justify="center">
|
||||
<el-form-item class="descriptionWide" v-if="isBackup()">
|
||||
<template #label>
|
||||
@ -301,6 +301,7 @@ import { oneDark } from '@codemirror/theme-one-dark';
|
||||
import { MsgError, MsgInfo, MsgSuccess } from '@/utils/message';
|
||||
|
||||
const loading = ref();
|
||||
const refresh = ref(false);
|
||||
const hasRecords = ref();
|
||||
|
||||
let timer: NodeJS.Timer | null = null;
|
||||
@ -324,7 +325,7 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||
search(true);
|
||||
timer = setInterval(() => {
|
||||
onRefresh();
|
||||
}, 1000 * 10);
|
||||
}, 1000 * 5);
|
||||
};
|
||||
|
||||
const shortcuts = [
|
||||
@ -402,10 +403,7 @@ const onHandle = async (row: Cronjob.CronjobInfo) => {
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
searchInfo.pageSize = searchInfo.pageSize * searchInfo.page;
|
||||
searchInfo.page = 1;
|
||||
records.value = [];
|
||||
search(false);
|
||||
onRefresh();
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
@ -483,7 +481,15 @@ const onRefresh = async () => {
|
||||
status: searchInfo.status,
|
||||
};
|
||||
const res = await searchRecords(params);
|
||||
records.value = res.data.items || [];
|
||||
if (res.data.items) {
|
||||
records.value = res.data.items;
|
||||
hasRecords.value = true;
|
||||
currentRecord.value = records.value[0];
|
||||
} else {
|
||||
records.value = [];
|
||||
hasRecords.value = false;
|
||||
refresh.value = !refresh.value;
|
||||
}
|
||||
};
|
||||
|
||||
const onDownload = async (record: any, backupID: number) => {
|
||||
|
Loading…
Reference in New Issue
Block a user