Skip to content

Commit 3e623eb

Browse files
fix: add action queue limits to prevent memory overflow
Caps pending actions at 50 with graceful degradation via warning alerts. Prevents unbounded memory growth during rapid AI code generation. Part of Phase 3 fix for issue #59.
1 parent 8085508 commit 3e623eb

1 file changed

Lines changed: 25 additions & 1 deletion

File tree

app/lib/stores/workbench.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {
99
import { webcontainer, setupWebContainerEventHandlers } from '~/lib/webcontainer';
1010
import type { ITerminal } from '~/types/terminal';
1111
import { unreachable } from '~/utils/unreachable';
12+
import { createScopedLogger } from '~/utils/logger';
1213
import { EditorStore } from './editor';
1314
import { FilesStore, type FileMap } from './files';
1415
import { PreviewsStore } from './previews';
@@ -27,6 +28,8 @@ import { diffApprovalStore } from './settings';
2728

2829
const { saveAs } = fileSaver;
2930

31+
const logger = createScopedLogger('WorkbenchStore');
32+
3033
const DEFAULT_ACTION_SAMPLE_INTERVAL = 500;
3134

3235
export interface ArtifactState {
@@ -88,12 +91,15 @@ type Artifacts = MapStore<Record<string, ArtifactState>>;
8891
export type WorkbenchViewType = 'code' | 'diff' | 'preview' | 'progress';
8992

9093
export class WorkbenchStore {
94+
static readonly MAX_PENDING_ACTIONS = 50;
95+
9196
#previewsStore = new PreviewsStore(webcontainer);
9297
#filesStore = new FilesStore(webcontainer);
9398
#editorStore = new EditorStore(this.#filesStore);
9499
#terminalStore = new TerminalStore(webcontainer);
95100

96101
#reloadedMessages = new Set<string>();
102+
#actionQueueDepth = 0;
97103

98104
artifacts: Artifacts = import.meta.hot?.data.artifacts ?? map({});
99105
thinkingArtifacts: MapStore<Record<string, ThinkingArtifactState>> =
@@ -157,7 +163,25 @@ export class WorkbenchStore {
157163
}
158164

159165
addToExecutionQueue(callback: () => Promise<void>) {
160-
this.#globalExecutionQueue = this.#globalExecutionQueue.then(() => callback());
166+
if (this.#actionQueueDepth >= WorkbenchStore.MAX_PENDING_ACTIONS) {
167+
logger.warn(`Action queue full (${this.#actionQueueDepth}), dropping action to prevent memory overflow`);
168+
169+
this.actionAlert.set({
170+
type: 'warning',
171+
title: 'Action Queue Full',
172+
description: 'Too many pending actions. Slowing down to prevent crashes.',
173+
});
174+
175+
return;
176+
}
177+
178+
this.#actionQueueDepth++;
179+
180+
this.#globalExecutionQueue = this.#globalExecutionQueue
181+
.then(() => callback())
182+
.finally(() => {
183+
this.#actionQueueDepth--;
184+
});
161185
}
162186

163187
get previews() {

0 commit comments

Comments
 (0)