Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set higher timeouts for import/export wp-cli commands #904

Merged
merged 7 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,9 @@ export const DAY_MS = HOUR_MS * 24;
// IMPORTANT: When updating this value, we need to update the string located in `AIClearHistoryReminder` component.
// Reference: https://github.com/Automattic/studio/blob/3dd5c58cdb7998e458d191e508e8e859177225a9/src/components/ai-clear-history-reminder.tsx#L78
export const CLEAR_HISTORY_REMINDER_TIME = 2 * HOUR_MS; // In milliseconds

// WP-CLI
export const WP_CLI_DEFAULT_RESPONSE_TIMEOUT = 5 * 60 * 1000; // 5min
export const WP_CLI_IMPORT_EXPORT_RESPONSE_TIMEOUT_IN_HRS = 6;
export const WP_CLI_IMPORT_EXPORT_RESPONSE_TIMEOUT =
WP_CLI_IMPORT_EXPORT_RESPONSE_TIMEOUT_IN_HRS * 60 * 60 * 1000; // 6hr
15 changes: 14 additions & 1 deletion src/hooks/use-import-export.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as Sentry from '@sentry/electron/renderer';
import { __ } from '@wordpress/i18n';
import { __, sprintf } from '@wordpress/i18n';
import { createContext, useMemo, useState, useCallback, useContext } from 'react';
import { WP_CLI_IMPORT_EXPORT_RESPONSE_TIMEOUT_IN_HRS } from 'src/constants';
import { useIpcListener } from 'src/hooks/use-ipc-listener';
import { useSiteDetails } from 'src/hooks/use-site-details';
import { getIpcApi } from 'src/lib/get-ipc-api';
Expand Down Expand Up @@ -92,6 +93,18 @@ export const ImportExportProvider = ( { children }: { children: React.ReactNode
'The ZIP archive is invalid. Try to unpack and pack it again. If this problem persists, please contact support.'
),
} );
} else if (
( error as Error ).message.includes( 'WP-CLI command was canceled (timed out)' )
) {
await getIpcApi().showErrorMessageBox( {
title: __( 'Failed importing site' ),
message: sprintf(
__(
'The import process timed out after %d hours, which can occur when processing very large imports. If the issue persists, please contact support.'
),
WP_CLI_IMPORT_EXPORT_RESPONSE_TIMEOUT_IN_HRS
),
} );
} else {
await getIpcApi().showErrorMessageBox( {
title: __( 'Failed importing site' ),
Expand Down
4 changes: 2 additions & 2 deletions src/lib/import-export/import/importers/importer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ abstract class BaseImporter extends EventEmitter implements Importer {
);

if ( stderr ) {
console.error( `Warning during import of ${ sqlFile }:`, stderr );
console.error( `Error during import of ${ sqlFile }:`, stderr );
}

if ( exitCode ) {
throw new Error( 'Database import failed' );
throw new Error( 'Database import failed: ' + stderr );
}
} finally {
await this.safelyDeletePath( tmpPath );
Expand Down
12 changes: 9 additions & 3 deletions src/lib/wp-cli-process.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { app, utilityProcess, UtilityProcess } from 'electron';
import * as Sentry from '@sentry/electron/renderer';
import {
WP_CLI_DEFAULT_RESPONSE_TIMEOUT as DEFAULT_RESPONSE_TIMEOUT,
WP_CLI_IMPORT_EXPORT_RESPONSE_TIMEOUT as IMPORT_EXPORT_RESPONSE_TIMEOUT,
} from 'src/constants';
import { executeWPCli } from 'vendor/wp-now/src/execute-wp-cli';

// This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Webpack
Expand All @@ -11,8 +15,6 @@ export type MessageName = 'execute';
export type WpCliResult = ReturnType< typeof executeWPCli >;
export type MessageCanceled = { error: Error; canceled: boolean };

const DEFAULT_RESPONSE_TIMEOUT = 300 * 1000;

export default class WpCliProcess {
lastMessageId = 0;
process?: UtilityProcess;
Expand Down Expand Up @@ -62,7 +64,11 @@ export default class WpCliProcess {
args,
phpVersion,
} );
return await this.waitForResponse( message, messageId );
const timeout =
args[ 0 ] === 'sqlite' && [ 'import', 'export' ].includes( args[ 1 ] )
? IMPORT_EXPORT_RESPONSE_TIMEOUT
: DEFAULT_RESPONSE_TIMEOUT;
return await this.waitForResponse( message, messageId, timeout );
}

async stop() {
Expand Down
12 changes: 10 additions & 2 deletions src/site-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,19 @@ export class SiteServer {
return await this.wpCliExecutor.execute( wpCliArgs as string[], { phpVersion } );
} catch ( error ) {
if ( ( error as MessageCanceled )?.canceled ) {
return { stdout: '', stderr: 'wp-cli command canceled', exitCode: 1 };
return {
stdout: '',
stderr: 'WP-CLI command was canceled (timed out)',
exitCode: 1,
};
}

Sentry.captureException( error );
return { stdout: '', stderr: 'error when executing wp-cli command', exitCode: 1 };
return {
stdout: '',
stderr: `Error executing WP-CLI command: ${ ( error as MessageCanceled ).error.message }`,
exitCode: 1,
};
}
}

Expand Down
Loading