fix(duckdb): add worker process isolation

This commit is contained in:
miracle authored and GitHub committed 2026-07-04 23:43:22 +08:00
1 parent 6529f22fed
commit 454457f191
26 files changed
+1694 -14

No files matched your search

@@ -74,6 +74,7 @@ import { EMPTY_TABLE_COLUMN_TEMPLATE_DATA_TYPE, parseTableColumnTemplateFields,
import { buildMcpCodexConfig, buildMcpJsonConfig, buildMcpOpenCodeConfig, buildMcpVsCodeConfig, type McpEnvEntry, type McpLaunchConfig } from "@/lib/mcp/mcpConfigTemplates";
import { isWindows } from "@/lib/backend/platform";
import { combineDataTypeForDatabase, dataTypeLengthInputValue, getDataTypeOptions, getDefaultLengthForType, isDataTypeLengthDisabled, splitDataType } from "@/lib/table/tableStructureEditorState";
import { useToast } from "@/composables/useToast";
import type { DatabaseType, SqlSnippet } from "@/types/database";
import { uuid } from "@/lib/common/utils";
import { DEFAULT_SQL_SNIPPETS } from "@/lib/sql/sqlCompletion";
@@ -90,6 +91,7 @@ import { apiUrl } from "@/lib/common/webPath";
import { DEFAULT_UI_FONT_FAMILY, SYSTEM_UI_FONT_FAMILY } from "@/lib/app/appFonts";
const { t } = useI18n();
const { toast } = useToast();
const settingsStore = useSettingsStore();
const connectionStore = useConnectionStore();
const savedSqlStore = useSavedSqlStore();
@@ -227,6 +229,10 @@ const editQuitOnClose = ref(settingsStore.desktopSettings.quit_on_close);
const desktopCloseBehaviorResetPending = ref(false);
const editIconTheme = ref<DesktopIconTheme>(settingsStore.desktopSettings.icon_theme);
const editDebugLoggingEnabled = ref(settingsStore.desktopSettings.debug_logging_enabled);
const editDuckDbWorkerProcessIsolation = ref(settingsStore.desktopSettings.duckdb_worker_process_isolation);
const startupDuckDbWorkerProcessIsolation = ref(settingsStore.desktopSettings.duckdb_worker_process_isolation);
const duckDbWorkerStartupCaptured = ref(false);
const duckDbRestarting = ref(false);
const editSidebarTablePageSize = ref(settingsStore.desktopSettings.sidebar_table_page_size ?? DEFAULT_SIDEBAR_TABLE_PAGE_SIZE);
const debugLogCopied = ref(false);
const debugLogDownloaded = ref(false);
@@ -526,6 +532,7 @@ watch(
editQuitOnClose.value = settingsStore.desktopSettings.quit_on_close;
editIconTheme.value = settingsStore.desktopSettings.icon_theme;
editDebugLoggingEnabled.value = settingsStore.desktopSettings.debug_logging_enabled;
editDuckDbWorkerProcessIsolation.value = settingsStore.desktopSettings.duckdb_worker_process_isolation;
editSidebarTablePageSize.value = settingsStore.desktopSettings.sidebar_table_page_size ?? DEFAULT_SIDEBAR_TABLE_PAGE_SIZE;
editShowColumnCommentsInHeader.value = settingsStore.editorSettings.showColumnCommentsInHeader;
editShowColumnTypesInHeader.value = settingsStore.editorSettings.showColumnTypesInHeader;
@@ -569,6 +576,7 @@ const formatterEditorShortcutIds: ShortcutActionId[] = ["formatSql", "find", "re
const formatterEditorShortcutDefinitions = computed(() => formatterEditorShortcutIds.map((id) => SHORTCUT_DEFINITIONS.find((definition) => definition.id === id)).filter((definition): definition is (typeof SHORTCUT_DEFINITIONS)[number] => !!definition));
const hasShortcutConflicts = computed(() => shortcutConflicts.value.length > 0);
const shortcutsChanged = computed(() => JSON.stringify(editShortcuts.value) !== JSON.stringify(settingsStore.editorSettings.shortcuts));
const duckDbWorkerProcessIsolationRequiresRestart = computed(() => editDuckDbWorkerProcessIsolation.value !== startupDuckDbWorkerProcessIsolation.value);
const hasBlockingShortcutConflicts = computed(() => shortcutsChanged.value && hasShortcutConflicts.value);
const hasBlockingFormatterConfig = computed(() => activeSettingsTab.value === "formatter" && !sqlFormatterConfigValid.value);
const hasApplyBlocker = computed(() => hasBlockingShortcutConflicts.value || hasBlockingFormatterConfig.value);
@@ -596,6 +604,7 @@ function hasChanges(): boolean {
editQuitOnClose.value !== settingsStore.desktopSettings.quit_on_close ||
editIconTheme.value !== settingsStore.desktopSettings.icon_theme ||
editDebugLoggingEnabled.value !== settingsStore.desktopSettings.debug_logging_enabled ||
editDuckDbWorkerProcessIsolation.value !== settingsStore.desktopSettings.duckdb_worker_process_isolation ||
editSidebarTablePageSize.value !== (settingsStore.desktopSettings.sidebar_table_page_size ?? DEFAULT_SIDEBAR_TABLE_PAGE_SIZE) ||
editShowColumnCommentsInHeader.value !== settingsStore.editorSettings.showColumnCommentsInHeader ||
editShowColumnTypesInHeader.value !== settingsStore.editorSettings.showColumnTypesInHeader ||
@@ -680,6 +689,7 @@ async function persistSettings() {
close_action_prompted: desktopCloseBehaviorResetPending.value ? false : true,
icon_theme: editIconTheme.value,
debug_logging_enabled: editDebugLoggingEnabled.value,
duckdb_worker_process_isolation: editDuckDbWorkerProcessIsolation.value,
sidebar_table_page_size: editSidebarTablePageSize.value,
});
desktopCloseBehaviorResetPending.value = false;
@@ -699,6 +709,20 @@ async function applySettingsAndClose() {
closeSettings();
}
async function restartDbxForDuckDbIsolation() {
if (duckDbRestarting.value || hasApplyBlocker.value || isWeb) return;
duckDbRestarting.value = true;
try {
await persistSettings();
const { relaunch } = await import("@tauri-apps/plugin-process");
await relaunch();
} catch (e: any) {
toast(t("settings.restartDbxFailed", { error: e?.message || String(e) }), 5000);
} finally {
duckDbRestarting.value = false;
}
}
function resetDefaultsForTab(tab: SettingsCategory) {
if (tab === "editor") {
editFontFamily.value = DEFAULT_EDITOR_SETTINGS.fontFamily;
@@ -747,6 +771,7 @@ function resetDefaultsForTab(tab: SettingsCategory) {
editDataGridQuickEntry.value = DEFAULT_EDITOR_SETTINGS.dataGridQuickEntry;
editInfiniteScroll.value = DEFAULT_EDITOR_SETTINGS.infiniteScroll;
editInfiniteScrollMaxRows.value = DEFAULT_EDITOR_SETTINGS.infiniteScrollMaxRows;
editDuckDbWorkerProcessIsolation.value = DEFAULT_DESKTOP_SETTINGS.duckdb_worker_process_isolation;
editTableColumnTemplateRows.value = tableColumnTemplateRowsFromSettings(DEFAULT_EDITOR_SETTINGS.tableColumnTemplateFields);
editExportBatchSize.value = DEFAULT_EDITOR_SETTINGS.exportBatchSize;
editExportRowLimitEnabled.value = DEFAULT_EDITOR_SETTINGS.exportRowLimitEnabled;
@@ -784,6 +809,7 @@ function resetAllDefaults() {
desktopCloseBehaviorResetPending.value = true;
editIconTheme.value = DEFAULT_DESKTOP_SETTINGS.icon_theme;
editDebugLoggingEnabled.value = DEFAULT_DESKTOP_SETTINGS.debug_logging_enabled;
editDuckDbWorkerProcessIsolation.value = DEFAULT_DESKTOP_SETTINGS.duckdb_worker_process_isolation;
editSidebarTablePageSize.value = DEFAULT_SIDEBAR_TABLE_PAGE_SIZE;
editShowColumnCommentsInHeader.value = DEFAULT_EDITOR_SETTINGS.showColumnCommentsInHeader;
editShowColumnTypesInHeader.value = DEFAULT_EDITOR_SETTINGS.showColumnTypesInHeader;
@@ -1462,6 +1488,11 @@ watch(
editQuitOnClose.value = settingsStore.desktopSettings.quit_on_close;
editIconTheme.value = settingsStore.desktopSettings.icon_theme;
editDebugLoggingEnabled.value = settingsStore.desktopSettings.debug_logging_enabled;
editDuckDbWorkerProcessIsolation.value = settingsStore.desktopSettings.duckdb_worker_process_isolation;
if (!duckDbWorkerStartupCaptured.value) {
startupDuckDbWorkerProcessIsolation.value = settingsStore.desktopSettings.duckdb_worker_process_isolation;
duckDbWorkerStartupCaptured.value = true;
}
editSidebarTablePageSize.value = settingsStore.desktopSettings.sidebar_table_page_size ?? DEFAULT_SIDEBAR_TABLE_PAGE_SIZE;
webdavPassword.value = "";
webdavSecretsPassphrase.value = "";
@@ -2873,6 +2904,35 @@ onUnmounted(cleanupPreviewEditor);
<!-- Data Tab -->
<section v-else-if="activeSettingsTab === 'data'" class="flex flex-col gap-5 py-2">
<template v-if="!isWeb">
<div class="space-y-3">
<div class="text-sm font-medium text-muted-foreground">DuckDB</div>
<div class="flex items-start justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
<div class="space-y-1">
<Label for="duckdb-worker-process-isolation">
{{ t("settings.duckDbWorkerProcessIsolation") }}
</Label>
<p class="text-xs text-muted-foreground">
{{ t("settings.duckDbWorkerProcessIsolationDescription") }}
</p>
<div v-if="duckDbWorkerProcessIsolationRequiresRestart" class="flex flex-wrap items-center gap-2 pt-1">
<p class="text-xs font-medium text-amber-600 dark:text-amber-400">
{{ t("settings.duckDbWorkerProcessIsolationRestartRequired") }}
</p>
<Button type="button" variant="outline" size="sm" class="h-7 gap-1.5 px-2 text-xs" :disabled="duckDbRestarting || hasApplyBlocker" @click="restartDbxForDuckDbIsolation">
<Loader2 v-if="duckDbRestarting" class="size-3.5 animate-spin" />
<RefreshCw v-else class="size-3.5" />
{{ t("settings.restartDbx") }}
</Button>
</div>
</div>
<Switch id="duckdb-worker-process-isolation" v-model="editDuckDbWorkerProcessIsolation" class="mt-0.5" />
</div>
</div>
<Separator />
</template>
<div class="space-y-3">
<div class="text-sm font-medium text-muted-foreground">{{ t("settings.exportSection") }}</div>
<div class="space-y-2">