feat: Database restore supports timeout settings (#11338)

This commit is contained in:
ssongliu 2025-12-15 18:40:37 +08:00 committed by GitHub
parent 11764e1ba5
commit 2fdb1700e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 75 additions and 4 deletions

View file

@ -83,6 +83,7 @@ type CommonRecover struct {
Secret string `json:"secret"`
TaskID string `json:"taskID"`
BackupRecordID uint `json:"backupRecordID"`
Timeout int `json:"timeout"`
}
type RecordSearch struct {

View file

@ -193,7 +193,16 @@ func handleMysqlRecover(req dto.CommonRecover, parentTask *task.Task, isRollback
return recoverDatabase(parentTask)
}
itemTask.AddSubTaskWithOps(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil, 0, 3*time.Hour)
var timeout time.Duration
switch req.Timeout {
case -1:
timeout = 0
case 0:
timeout = 3 * time.Hour
default:
timeout = time.Duration(req.Timeout) * time.Second
}
itemTask.AddSubTaskWithOps(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil, 0, timeout)
go func() {
_ = itemTask.Execute()
}()

View file

@ -187,7 +187,16 @@ func handlePostgresqlRecover(req dto.CommonRecover, parentTask *task.Task, isRol
return recoverDatabase(parentTask)
}
itemTask.AddSubTaskWithOps(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil, 0, 3*time.Hour)
var timeout time.Duration
switch req.Timeout {
case -1:
timeout = 0
case 0:
timeout = 3 * time.Hour
default:
timeout = time.Duration(req.Timeout) * time.Second
}
itemTask.AddSubTaskWithOps(i18n.GetMsgByKey("TaskRecover"), recoverDatabase, nil, 0, timeout)
go func() {
_ = itemTask.Execute()
}()

View file

@ -226,6 +226,9 @@ func (s *SubTask) Execute() error {
s.RootTask.Log(i18n.GetWithName("TaskRetry", strconv.Itoa(i)))
}
ctx, cancel := context.WithTimeout(context.Background(), s.Timeout)
if s.Timeout == 0 {
ctx, cancel = context.WithCancel(context.Background())
}
defer cancel()
done := make(chan error)

View file

@ -110,6 +110,22 @@
<el-form-item :label="$t('setting.compressPassword')">
<el-input v-model="secret" :placeholder="$t('setting.backupRecoverMessage')" />
</el-form-item>
<el-form-item
v-if="!isBackup && type !== 'app' && type !== 'website'"
:label="$t('cronjob.timeout')"
prop="timeoutItem"
>
<el-input type="number" class="selectClass" v-model.number="timeoutItem">
<template #append>
<el-select v-model="timeoutUnit" style="width: 80px">
<el-option :label="$t('commons.units.second')" value="s" />
<el-option :label="$t('commons.units.minute')" value="m" />
<el-option :label="$t('commons.units.hour')" value="h" />
</el-select>
</template>
</el-input>
<span class="input-help">{{ $t('database.recoverTimeoutHelper') }}</span>
</el-form-item>
<el-form-item v-if="isBackup" :label="$t('commons.table.description')">
<el-input type="textarea" :autosize="{ minRows: 2, maxRows: 5 }" v-model="description" />
</el-form-item>
@ -133,7 +149,7 @@
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { computeSize, dateFormat, downloadFile, newUUID } from '@/utils/util';
import { computeSize, dateFormat, downloadFile, newUUID, transferTimeToSecond } from '@/utils/util';
import {
getLocalBackupDir,
handleBackup,
@ -182,6 +198,8 @@ const backupPath = ref();
const status = ref();
const secret = ref();
const description = ref();
const timeoutItem = ref(30);
const timeoutUnit = ref('m');
const open = ref();
const isBackup = ref();
@ -314,6 +332,7 @@ const recover = async (row?: any) => {
secret: secret.value,
taskID: taskID,
backupRecordID: row.id,
timeout: timeoutItem.value === -1 ? -1 : transferTimeToSecond(timeoutItem.value + timeoutUnit.value),
};
loading.value = true;
await handleRecover(params)

View file

@ -94,6 +94,22 @@
<el-form-item :label="$t('setting.compressPassword')">
<el-input v-model="secret" :placeholder="$t('setting.backupRecoverMessage')" />
</el-form-item>
<el-form-item
v-if="type !== 'app' && type !== 'website'"
:label="$t('cronjob.timeout')"
prop="timeoutItem"
>
<el-input type="number" class="selectClass" v-model.number="timeoutItem">
<template #append>
<el-select v-model="timeoutUnit" style="width: 80px">
<el-option :label="$t('commons.units.second')" value="s" />
<el-option :label="$t('commons.units.minute')" value="m" />
<el-option :label="$t('commons.units.hour')" value="h" />
</el-select>
</template>
</el-input>
<span class="input-help">{{ $t('database.recoverTimeoutHelper') }}</span>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
@ -115,7 +131,7 @@
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { computeSize, newUUID } from '@/utils/util';
import { computeSize, newUUID, transferTimeToSecond } from '@/utils/util';
import i18n from '@/lang';
import { UploadFile, UploadFiles, UploadInstance, UploadProps, UploadRawFile, genFileId } from 'element-plus';
import { File } from '@/api/interface/file';
@ -152,6 +168,8 @@ const name = ref();
const detailName = ref();
const remark = ref();
const secret = ref();
const timeoutItem = ref(30);
const timeoutUnit = ref('m');
const taskLogRef = ref();
const recoverDialog = ref();
@ -261,6 +279,7 @@ const onHandleRecover = async () => {
file: baseDir.value + currentRow.value.name,
secret: secret.value,
taskID: newUUID(),
timeout: timeoutItem.value === -1 ? -1 : transferTimeToSecond(timeoutItem.value + timeoutUnit.value),
};
loading.value = true;
await handleRecoverByUpload(params)

View file

@ -513,6 +513,7 @@ const message = {
changeConnHelper: 'This operation will modify the current database {0}. Do you want to continue?',
changePasswordHelper:
'The database has been associated with an application. Changing the password will change the database password of the application at the same time. The change takes effect after the application restarts.',
recoverTimeoutHelper: '-1 means no timeout limit',
confChange: 'Configuration',
confNotFound:

View file

@ -517,6 +517,8 @@ const message = {
changeConnHelper: 'Esta operación modificará la base de datos actual {0}. ¿Desea continuar?',
changePasswordHelper:
'La base de datos ha sido asociada a una aplicación. Cambiar la contraseña también cambiará la contraseña de la base de datos en la aplicación. El cambio se aplica después de reiniciar la aplicación.',
recoverTimeoutHelper: '-1 significa sin límite de tiempo de espera',
confChange: 'Configuración',
confNotFound:
'No se pudo encontrar el archivo de configuración. Por favor actualice la aplicación a la última versión en la tienda y vuelva a intentarlo.',

View file

@ -501,6 +501,7 @@ const message = {
changeConnHelper: 'この操作は現在のデータベース {0} を変更します続行しますか',
changePasswordHelper:
'データベースはアプリケーションに関連付けられていますパスワードを変更するとアプリケーションのデータベースパスワードが同時に変更されますアプリケーションが再起動した後変更は有効になります',
recoverTimeoutHelper: '-1 はタイムアウト制限なしを意味します',
confChange: '構成',
confNotFound:

View file

@ -504,6 +504,7 @@ const message = {
changeConnHelper: ' 작업은 현재 데이터베이스 {0}() 수정합니다. 계속하시겠습니까?',
changePasswordHelper:
'데이터베이스가 애플리케이션과 연결되어 있습니다. 비밀번호를 변경하면 애플리케이션의 데이터베이스 비밀번호도 변경됩니다. 변경 사항은 애플리케이션이 재시작된 후에 적용됩니다.',
recoverTimeoutHelper: '-1 제한 시간 제한 없음을 의미합니다',
confChange: '설정',
confNotFound:
'설정 파일을 찾을 없습니다. 스토어에서 애플리케이션을 최신 버전으로 업그레이드하고 다시 시도해주세요!',

View file

@ -510,6 +510,7 @@ const message = {
changeConnHelper: 'Operasi ini akan mengubah pangkalan data semasa {0}. Adakah anda ingin meneruskan?',
changePasswordHelper:
'Pangkalan data telah dikaitkan dengan aplikasi. Menukar kata laluan akan menukar kata laluan pangkalan data aplikasi pada masa yang sama. Perubahan ini akan berkuat kuasa selepas aplikasi dimulakan semula.',
recoverTimeoutHelper: '-1 bermaksud tiada had masa tamat',
confChange: 'Konfigurasi',
confNotFound:

View file

@ -508,6 +508,7 @@ const message = {
changeConnHelper: 'Esta operação modificará o banco de dados atual {0}. Deseja continuar?',
changePasswordHelper:
'O banco de dados está associado a um aplicativo. Alterar a senha alterará a senha do banco de dados do aplicativo ao mesmo tempo. A mudança surtirá efeito após a reinicialização do aplicativo.',
recoverTimeoutHelper: '-1 significa sem limite de tempo limite',
confChange: 'Configuração',
confNotFound:

View file

@ -502,6 +502,7 @@ const message = {
changePassword: 'Пароль',
changePasswordHelper:
'База данных была связана с приложением. Изменение пароля изменит пароль базы данных приложения одновременно. Изменение вступит в силу после перезапуска приложения.',
recoverTimeoutHelper: '-1 означает отсутствие ограничения по времени ожидания',
confChange: 'Конфигурация',
confNotFound:

View file

@ -516,6 +516,7 @@ const message = {
changeConnHelper: 'Bu işlem mevcut {0} veritabanını değiştirecek. Devam etmek istiyor musunuz?',
changePasswordHelper:
'Veritabanı bir uygulamayla ilişkilendirildi. Şifre değiştirmek aynı zamanda uygulamanın veritabanı şifresini de değiştirecek. Değişiklik uygulama yeniden başlatıldıktan sonra etkili olur.',
recoverTimeoutHelper: '-1, zaman ımı sınırı olmadığı anlamına gelir',
confChange: 'Yapılandırma',
confNotFound:

View file

@ -496,6 +496,7 @@ const message = {
changePassword: '改密',
changeConnHelper: '此操作將修改目前資料庫 {0}是否繼續',
changePasswordHelper: '目前資料庫已經關聯應用修改密碼將同步修改應用中資料庫密碼修改後重啟生效',
recoverTimeoutHelper: '-1 表示不限制超時時間',
portHelper: '該埠為容器對外暴露埠修改需要單獨儲存並且重啟容器',

View file

@ -497,6 +497,7 @@ const message = {
changePassword: '改密',
changeConnHelper: '此操作将修改当前数据库 {0}是否继续',
changePasswordHelper: '当前数据库已经关联应用修改密码将同步修改应用中数据库密码修改后重启生效',
recoverTimeoutHelper: ' -1 表示不限制超时时间',
portHelper: '该端口为容器对外暴露端口修改需要单独保存并且重启容器',