Skip to content

Commit 3e50469

Browse files
fix(web): Fix multiple writes race condition on config file watcher (#398)
1 parent d0f9d43 commit 3e50469

4 files changed

Lines changed: 22 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111
- Add search context to ask sourcebot context selector. [#397](https://github.com/sourcebot-dev/sourcebot/pull/397)
1212

13+
### Fixed
14+
- Fixed multiple writes race condition on config file watcher. [#398](https://github.com/sourcebot-dev/sourcebot/pull/398)
15+
1316
## [4.6.0] - 2025-07-25
1417

1518
### Added

packages/web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
"ai": "5.0.0-beta.28",
112112
"ajv": "^8.17.1",
113113
"bcryptjs": "^3.0.2",
114+
"chokidar": "^4.0.3",
114115
"class-variance-authority": "^0.7.0",
115116
"client-only": "^0.0.1",
116117
"clsx": "^2.1.1",

packages/web/src/initialize.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ConnectionSyncStatus, OrgRole, Prisma, RepoIndexingStatus } from '@sour
22
import { env } from './env.mjs';
33
import { prisma } from "@/prisma";
44
import { SINGLE_TENANT_ORG_ID, SINGLE_TENANT_ORG_DOMAIN, SOURCEBOT_GUEST_USER_ID, SINGLE_TENANT_ORG_NAME } from './lib/constants';
5-
import { watch } from 'fs';
5+
import chokidar from 'chokidar';
66
import { ConnectionConfig } from '@sourcebot/schemas/v3/connection.type';
77
import { hasEntitlement, loadConfig, isRemotePath, syncSearchContexts } from '@sourcebot/shared';
88
import { isServiceError, getOrgMetadata } from './lib/utils';
@@ -227,9 +227,22 @@ const initSingleTenancy = async () => {
227227

228228
// watch for changes assuming it is a local file
229229
if (!isRemotePath(configPath)) {
230-
watch(configPath, () => {
230+
const watcher = chokidar.watch(configPath, {
231+
ignoreInitial: true, // Don't fire events for existing files
232+
awaitWriteFinish: {
233+
stabilityThreshold: 100, // File size stable for 100ms
234+
pollInterval: 100 // Check every 100ms
235+
},
236+
atomic: true // Handle atomic writes (temp file + rename)
237+
});
238+
239+
watcher.on('change', async () => {
231240
logger.info(`Config file ${configPath} changed. Re-syncing...`);
232-
syncDeclarativeConfig(configPath);
241+
try {
242+
await syncDeclarativeConfig(configPath);
243+
} catch (error) {
244+
logger.error(`Failed to sync config: ${error}`);
245+
}
233246
});
234247
}
235248
}

yarn.lock

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6606,6 +6606,7 @@ __metadata:
66066606
ai: "npm:5.0.0-beta.28"
66076607
ajv: "npm:^8.17.1"
66086608
bcryptjs: "npm:^3.0.2"
6609+
chokidar: "npm:^4.0.3"
66096610
class-variance-authority: "npm:^0.7.0"
66106611
client-only: "npm:^0.0.1"
66116612
clsx: "npm:^2.1.1"
@@ -8714,7 +8715,7 @@ __metadata:
87148715
languageName: node
87158716
linkType: hard
87168717

8717-
"chokidar@npm:^4.0.1":
8718+
"chokidar@npm:^4.0.1, chokidar@npm:^4.0.3":
87188719
version: 4.0.3
87198720
resolution: "chokidar@npm:4.0.3"
87208721
dependencies:

0 commit comments

Comments
 (0)