fix(web): Fix multiple writes race condition on config file watcher (#398)

This commit is contained in:
Brendan Kellam 2025-07-26 16:42:25 -07:00 committed by GitHub
parent d0f9d43624
commit 3e50469cf7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 22 additions and 4 deletions

View file

@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Add search context to ask sourcebot context selector. [#397](https://github.com/sourcebot-dev/sourcebot/pull/397) - 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 ## [4.6.0] - 2025-07-25
### Added ### Added

View file

@ -111,6 +111,7 @@
"ai": "5.0.0-beta.28", "ai": "5.0.0-beta.28",
"ajv": "^8.17.1", "ajv": "^8.17.1",
"bcryptjs": "^3.0.2", "bcryptjs": "^3.0.2",
"chokidar": "^4.0.3",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"client-only": "^0.0.1", "client-only": "^0.0.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",

View file

@ -2,7 +2,7 @@ import { ConnectionSyncStatus, OrgRole, Prisma, RepoIndexingStatus } from '@sour
import { env } from './env.mjs'; import { env } from './env.mjs';
import { prisma } from "@/prisma"; 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 { 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 { ConnectionConfig } from '@sourcebot/schemas/v3/connection.type';
import { hasEntitlement, loadConfig, isRemotePath, syncSearchContexts } from '@sourcebot/shared'; import { hasEntitlement, loadConfig, isRemotePath, syncSearchContexts } from '@sourcebot/shared';
import { isServiceError, getOrgMetadata } from './lib/utils'; import { isServiceError, getOrgMetadata } from './lib/utils';
@ -227,9 +227,22 @@ const initSingleTenancy = async () => {
// watch for changes assuming it is a local file // watch for changes assuming it is a local file
if (!isRemotePath(configPath)) { 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...`); logger.info(`Config file ${configPath} changed. Re-syncing...`);
syncDeclarativeConfig(configPath); try {
await syncDeclarativeConfig(configPath);
} catch (error) {
logger.error(`Failed to sync config: ${error}`);
}
}); });
} }
} }

View file

@ -6606,6 +6606,7 @@ __metadata:
ai: "npm:5.0.0-beta.28" ai: "npm:5.0.0-beta.28"
ajv: "npm:^8.17.1" ajv: "npm:^8.17.1"
bcryptjs: "npm:^3.0.2" bcryptjs: "npm:^3.0.2"
chokidar: "npm:^4.0.3"
class-variance-authority: "npm:^0.7.0" class-variance-authority: "npm:^0.7.0"
client-only: "npm:^0.0.1" client-only: "npm:^0.0.1"
clsx: "npm:^2.1.1" clsx: "npm:^2.1.1"
@ -8714,7 +8715,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"chokidar@npm:^4.0.1": "chokidar@npm:^4.0.1, chokidar@npm:^4.0.3":
version: 4.0.3 version: 4.0.3
resolution: "chokidar@npm:4.0.3" resolution: "chokidar@npm:4.0.3"
dependencies: dependencies: