-
Notifications
You must be signed in to change notification settings - Fork 746
fix(sagemaker): Fix race-condition with multiple remote spaces trying to reconnect #7684
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,10 @@ export { open } | |
| export const mappingFilePath = join(os.homedir(), '.aws', '.sagemaker-space-profiles') | ||
| const tempFilePath = `${mappingFilePath}.tmp` | ||
|
|
||
| // Simple file lock to prevent concurrent writes | ||
| let isWriting = false | ||
| const writeQueue: Array<() => Promise<void>> = [] | ||
|
|
||
| /** | ||
| * Reads the local endpoint info file (default or via env) and returns pid & port. | ||
| * @throws Error if the file is missing, invalid JSON, or missing fields | ||
|
|
@@ -100,14 +104,45 @@ export async function readMapping() { | |
| } | ||
|
|
||
| /** | ||
| * Writes the mapping to a temp file and atomically renames it to the target path. | ||
| * Processes the write queue to ensure only one write operation happens at a time. | ||
| */ | ||
| export async function writeMapping(mapping: SpaceMappings) { | ||
| async function processWriteQueue() { | ||
| if (isWriting || writeQueue.length === 0) { | ||
| return | ||
| } | ||
|
|
||
| isWriting = true | ||
| try { | ||
| const json = JSON.stringify(mapping, undefined, 2) | ||
| await fs.writeFile(tempFilePath, json) | ||
| await fs.rename(tempFilePath, mappingFilePath) | ||
| } catch (err) { | ||
| throw new Error(`Failed to write mapping file: ${err instanceof Error ? err.message : String(err)}`) | ||
| while (writeQueue.length > 0) { | ||
| const writeOperation = writeQueue.shift()! | ||
| await writeOperation() | ||
| } | ||
| } finally { | ||
| isWriting = false | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Writes the mapping to a temp file and atomically renames it to the target path. | ||
| * Uses a queue to prevent race conditions when multiple requests try to write simultaneously. | ||
| */ | ||
| export async function writeMapping(mapping: SpaceMappings) { | ||
| return new Promise<void>((resolve, reject) => { | ||
| const writeOperation = async () => { | ||
| try { | ||
| // Generate unique temp file name to avoid conflicts | ||
| const uniqueTempPath = `${tempFilePath}.${process.pid}.${Date.now()}` | ||
|
|
||
| const json = JSON.stringify(mapping, undefined, 2) | ||
| await fs.writeFile(uniqueTempPath, json) | ||
| await fs.rename(uniqueTempPath, mappingFilePath) | ||
| resolve() | ||
| } catch (err) { | ||
| reject(new Error(`Failed to write mapping file: ${err instanceof Error ? err.message : String(err)}`)) | ||
| } | ||
| } | ||
|
|
||
| writeQueue.push(writeOperation) | ||
| processWriteQueue().catch(reject) | ||
|
||
| }) | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.