From dc23da9f3ae80d2007d043ce27e04d9c94b53501 Mon Sep 17 00:00:00 2001 From: bkellam Date: Sat, 26 Jul 2025 15:09:09 -0700 Subject: [PATCH 1/2] switch to using chokidar --- packages/web/package.json | 1 + packages/web/src/initialize.ts | 19 ++++++++++++++++--- yarn.lock | 3 ++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/web/package.json b/packages/web/package.json index 6d5d518d..4e3e6950 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -111,6 +111,7 @@ "ai": "5.0.0-beta.28", "ajv": "^8.17.1", "bcryptjs": "^3.0.2", + "chokidar": "^4.0.3", "class-variance-authority": "^0.7.0", "client-only": "^0.0.1", "clsx": "^2.1.1", diff --git a/packages/web/src/initialize.ts b/packages/web/src/initialize.ts index df1d0839..4c7b0355 100644 --- a/packages/web/src/initialize.ts +++ b/packages/web/src/initialize.ts @@ -2,7 +2,7 @@ import { ConnectionSyncStatus, OrgRole, Prisma, RepoIndexingStatus } from '@sour import { env } from './env.mjs'; import { prisma } from "@/prisma"; import { SINGLE_TENANT_ORG_ID, SINGLE_TENANT_ORG_DOMAIN, SOURCEBOT_GUEST_USER_ID, SINGLE_TENANT_ORG_NAME } from './lib/constants'; -import { watch } from 'fs'; +import chokidar from 'chokidar'; import { ConnectionConfig } from '@sourcebot/schemas/v3/connection.type'; import { hasEntitlement, loadConfig, isRemotePath, syncSearchContexts } from '@sourcebot/shared'; import { isServiceError, getOrgMetadata } from './lib/utils'; @@ -227,9 +227,22 @@ const initSingleTenancy = async () => { // watch for changes assuming it is a local file if (!isRemotePath(configPath)) { - watch(configPath, () => { + const watcher = chokidar.watch(configPath, { + ignoreInitial: true, // Don't fire events for existing files + awaitWriteFinish: { + stabilityThreshold: 100, // File size stable for 100ms + pollInterval: 100 // Check every 100ms + }, + atomic: true // Handle atomic writes (temp file + rename) + }); + + watcher.on('change', async () => { logger.info(`Config file ${configPath} changed. Re-syncing...`); - syncDeclarativeConfig(configPath); + try { + await syncDeclarativeConfig(configPath); + } catch (error) { + logger.error(`Failed to sync config: ${error}`); + } }); } } diff --git a/yarn.lock b/yarn.lock index fca7192d..73069be5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6606,6 +6606,7 @@ __metadata: ai: "npm:5.0.0-beta.28" ajv: "npm:^8.17.1" bcryptjs: "npm:^3.0.2" + chokidar: "npm:^4.0.3" class-variance-authority: "npm:^0.7.0" client-only: "npm:^0.0.1" clsx: "npm:^2.1.1" @@ -8714,7 +8715,7 @@ __metadata: languageName: node linkType: hard -"chokidar@npm:^4.0.1": +"chokidar@npm:^4.0.1, chokidar@npm:^4.0.3": version: 4.0.3 resolution: "chokidar@npm:4.0.3" dependencies: From fcbdf6db48ec619cafabf00b757bf3b333ae4a36 Mon Sep 17 00:00:00 2001 From: bkellam Date: Sat, 26 Jul 2025 15:16:51 -0700 Subject: [PATCH 2/2] changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef0220d4..7e792039 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add search context to ask sourcebot context selector. [#397](https://github.com/sourcebot-dev/sourcebot/pull/397) +### Fixed +- Fixed multiple writes race condition on config file watcher. [#398](https://github.com/sourcebot-dev/sourcebot/pull/398) + ## [4.6.0] - 2025-07-25 ### Added