Skip to content

Commit 8ed432a

Browse files
authored
fix: handle parcel shutdown race condition (#834)
1 parent d8408db commit 8ed432a

File tree

4 files changed

+44
-3
lines changed

4 files changed

+44
-3
lines changed

apps/twig/src/main/services/file-watcher/service.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import fs from "node:fs/promises";
33
import path from "node:path";
44
import * as watcher from "@parcel/watcher";
55
import { app } from "electron";
6-
import { injectable, preDestroy } from "inversify";
6+
import { inject, injectable, preDestroy } from "inversify";
7+
import { MAIN_TOKENS } from "../../di/tokens.js";
78
import { logger } from "../../lib/logger.js";
89
import { TypedEventEmitter } from "../../lib/typed-event-emitter.js";
10+
import type { ProcessTrackingService } from "../process-tracking/service.js";
911
import {
1012
type DirectoryEntry,
1113
FileWatcherEvent,
@@ -35,6 +37,13 @@ interface RepoWatcher {
3537
export class FileWatcherService extends TypedEventEmitter<FileWatcherEvents> {
3638
private watchers = new Map<string, RepoWatcher>();
3739

40+
constructor(
41+
@inject(MAIN_TOKENS.ProcessTrackingService)
42+
private processTracking: ProcessTrackingService,
43+
) {
44+
super();
45+
}
46+
3847
async listDirectory(dirPath: string): Promise<DirectoryEntry[]> {
3948
try {
4049
const entries = await fs.readdir(dirPath, { withFileTypes: true });
@@ -144,6 +153,7 @@ export class FileWatcherService extends TypedEventEmitter<FileWatcherEvents> {
144153
return watcher.subscribe(
145154
repoPath,
146155
(err, events) => {
156+
if (this.processTracking.isShuttingDown) return;
147157
if (err) {
148158
this.handleWatcherError(err, repoPath);
149159
return;
@@ -221,6 +231,7 @@ export class FileWatcherService extends TypedEventEmitter<FileWatcherEvents> {
221231
try {
222232
const gitDir = await this.resolveGitDir(repoPath);
223233
return watcher.subscribe(gitDir, (err, events) => {
234+
if (this.processTracking.isShuttingDown) return;
224235
if (err) {
225236
log.error("Git watcher error:", err);
226237
return;

apps/twig/src/main/services/focus/service.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ import {
1515
StashPopSaga,
1616
StashPushSaga,
1717
} from "@twig/git/sagas/stash";
18-
import { injectable, preDestroy } from "inversify";
18+
import { inject, injectable, preDestroy } from "inversify";
19+
import { MAIN_TOKENS } from "../../di/tokens.js";
1920
import { logger } from "../../lib/logger";
2021
import { TypedEventEmitter } from "../../lib/typed-event-emitter";
2122
import { type FocusSession, focusStore } from "../../utils/store.js";
23+
import type { ProcessTrackingService } from "../process-tracking/service.js";
2224
import { getWorktreeLocation } from "../settingsStore";
2325
import type { FocusResult, StashResult } from "./schemas.js";
2426

@@ -49,6 +51,13 @@ export class FocusService extends TypedEventEmitter<FocusServiceEvents> {
4951
private mainRepoWatcher: watcher.AsyncSubscription | null = null;
5052
private watchedMainRepo: string | null = null;
5153

54+
constructor(
55+
@inject(MAIN_TOKENS.ProcessTrackingService)
56+
private processTracking: ProcessTrackingService,
57+
) {
58+
super();
59+
}
60+
5261
async startWatchingMainRepo(mainRepoPath: string): Promise<void> {
5362
if (this.watchedMainRepo === mainRepoPath && this.mainRepoWatcher) {
5463
return;
@@ -61,6 +70,10 @@ export class FocusService extends TypedEventEmitter<FocusServiceEvents> {
6170

6271
this.watchedMainRepo = mainRepoPath;
6372
this.mainRepoWatcher = await watcher.subscribe(gitDir, (err, events) => {
73+
if (this.processTracking.isShuttingDown) {
74+
return;
75+
}
76+
6477
if (err) {
6578
log.error("Main repo watcher error:", err);
6679
return;

apps/twig/src/main/services/focus/sync-service.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import {
88
} from "@twig/git/queries";
99
import { ApplyPatchSaga } from "@twig/git/sagas/patch";
1010
import ignore, { type Ignore } from "ignore";
11-
import { injectable, preDestroy } from "inversify";
11+
import { inject, injectable, preDestroy } from "inversify";
12+
import { MAIN_TOKENS } from "../../di/tokens.js";
1213
import { logger } from "../../lib/logger.js";
14+
import type { ProcessTrackingService } from "../process-tracking/service.js";
1315

1416
const log = logger.scope("focus-sync");
1517

@@ -46,6 +48,11 @@ export class FocusSyncService {
4648
/** Files we recently wrote - map of absolute path to write timestamp */
4749
private recentWrites: Map<string, number> = new Map();
4850

51+
constructor(
52+
@inject(MAIN_TOKENS.ProcessTrackingService)
53+
private processTracking: ProcessTrackingService,
54+
) {}
55+
4956
async startSync(mainRepoPath: string, worktreePath: string): Promise<void> {
5057
const [mainExists, worktreeExists] = await Promise.all([
5158
fs
@@ -99,6 +106,7 @@ export class FocusSyncService {
99106
const mainSubPromise = watcher.subscribe(
100107
mainRepoPath,
101108
(err, events) => {
109+
if (this.processTracking.isShuttingDown) return;
102110
if (err) {
103111
log.error("Main repo watcher error:", err);
104112
return;
@@ -128,6 +136,7 @@ export class FocusSyncService {
128136
const worktreeSubPromise = watcher.subscribe(
129137
worktreePath,
130138
(err, events) => {
139+
if (this.processTracking.isShuttingDown) return;
131140
if (err) {
132141
log.error("Worktree watcher error:", err);
133142
return;

apps/twig/src/main/services/process-tracking/service.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ export interface ProcessSnapshot {
3434

3535
@injectable()
3636
export class ProcessTrackingService {
37+
private _isShuttingDown = false;
38+
39+
get isShuttingDown(): boolean {
40+
return this._isShuttingDown;
41+
}
42+
3743
private processes = new Map<number, TrackedProcess>();
3844
private taskProcesses = new Map<string, Set<number>>();
3945

@@ -235,6 +241,8 @@ export class ProcessTrackingService {
235241

236242
@preDestroy()
237243
killAll(): void {
244+
this._isShuttingDown = true;
245+
238246
const count = this.processes.size;
239247
if (count > 0) {
240248
log.info(`Killing all tracked processes (${count} active)`);

0 commit comments

Comments
 (0)