fix(frontend): remove Automate operation timeout (#7082)

# Description of Changes

Remove the hard-coded five-minute client-side timeout from Automate
operations.

- Remove `AUTOMATION_CONSTANTS.OPERATION_TIMEOUT`.
- Let normal Automate requests use the API client's default no-timeout
behavior, matching regular tool execution.
- Preserve an explicitly supplied `AutomationProcessingOptions.timeout`
without applying a finite default.
- Add regression coverage verifying that Automate does not send a
client-side timeout by default.

Large PDF operations such as compression can legitimately take more than
five minutes. Previously, Axios aborted the frontend request after
300,000 ms even when the server and reverse proxy allowed the operation
to continue. The backend could continue processing while the frontend
discarded the result.

No significant implementation challenges were encountered.

Closes #7081 

## Testing

The following frontend checks passed:

- Proprietary frontend TypeScript typecheck
- ESLint with zero warnings
- Circular dependency check
- Theme colour lint
- Prettier formatting check
- Focused `automationExecutor.test.ts` regression test
- Complete Vitest suite: 165 test files and 1,354 tests passed

---

## Checklist

### General

- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [x] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(not applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(not applicable; no user-facing configuration changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(not applicable)

### Translations (if applicable)

- [ ] I ran
[`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md)
(not applicable)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(not applicable; no visual changes)

### Testing (if applicable)

- [ ] I have run `task check` to verify linters, typechecks, and tests
pass
- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing)
for more details.

Co-authored-by: Reece Browne <74901996+reecebrowne@users.noreply.github.com>
This commit is contained in:
staticdev
2026-08-12 15:30:53 +00:00
committed by GitHub
co-authored by Reece Browne
parent fdc1682863
commit c3802ac1ef
4 changed files with 54 additions and 8 deletions
@@ -3,9 +3,6 @@
*/
export const AUTOMATION_CONSTANTS = {
// Timeouts
OPERATION_TIMEOUT: 300000, // 5 minutes in milliseconds
// Default values
DEFAULT_TOOL_COUNT: 2,
MIN_TOOL_COUNT: 2,
@@ -1,5 +1,19 @@
import { describe, expect, test } from "vitest";
import { processMultiFileResponse } from "@app/utils/automationExecutor";
import { beforeEach, describe, expect, type Mock, test, vi } from "vitest";
import apiClient from "@app/services/apiClient";
import type { ToolRegistry } from "@app/data/toolsTaxonomy";
import { ToolType } from "@app/hooks/tools/shared/useToolOperation";
import {
executeToolOperation,
processMultiFileResponse,
} from "@app/utils/automationExecutor";
vi.mock("@app/services/apiClient", () => ({
default: {
post: vi.fn(),
},
}));
const mockedApiClient = vi.mocked(apiClient);
// Regression coverage for the automation-side mirror of the merge bug:
// non-canonical Content-Types previously misrouted a PDF into ZIP extraction
@@ -56,3 +70,39 @@ describe("processMultiFileResponse (automation execution)", () => {
expect(result[0].name).not.toMatch(/\.zip$/);
});
});
describe("executeToolOperation (automation execution)", () => {
beforeEach(() => {
vi.clearAllMocks();
(mockedApiClient.post as Mock).mockResolvedValue({
data: new Blob([PDF_BYTES], { type: "application/pdf" }),
headers: { "content-type": "application/pdf" },
});
});
test("does not impose a client-side operation timeout", async () => {
const toolRegistry = {
compress: {
operationConfig: {
operationType: "compress",
toolType: ToolType.singleFile,
endpoint: "/api/v1/misc/compress-pdf",
defaultParameters: {},
buildFormData: (_parameters: unknown, file: File) => {
const formData = new FormData();
formData.append("fileInput", file);
return formData;
},
},
},
} as unknown as ToolRegistry;
await executeToolOperation("compress", {}, inputFiles, toolRegistry);
expect(mockedApiClient.post).toHaveBeenCalledWith(
"/api/v1/misc/compress-pdf",
expect.any(FormData),
{ responseType: "blob" },
);
});
});
@@ -65,7 +65,6 @@ const executeApiRequest = async (
): Promise<File[]> => {
const response = await apiClient.post(endpoint, formData, {
responseType: "blob",
timeout: AUTOMATION_CONSTANTS.OPERATION_TIMEOUT,
});
return await processMultiFileResponse(
@@ -97,7 +97,7 @@ export class AutomationFileProcessor {
try {
const response = await apiClient.post(endpoint, formData, {
responseType: options.responseType || "blob",
timeout: options.timeout || AUTOMATION_CONSTANTS.OPERATION_TIMEOUT,
...(options.timeout !== undefined ? { timeout: options.timeout } : {}),
});
if (response.status !== 200) {
@@ -143,7 +143,7 @@ export class AutomationFileProcessor {
try {
const response = await apiClient.post(endpoint, formData, {
responseType: options.responseType || "blob",
timeout: options.timeout || AUTOMATION_CONSTANTS.OPERATION_TIMEOUT,
...(options.timeout !== undefined ? { timeout: options.timeout } : {}),
});
if (response.status !== 200) {