@@ -58,9 +58,7 @@ export class DiskBasedResultStorage implements AccuracyResultStorage {
5858
5959 async updateRunStatus ( commitSHA : string , runId : string , status : AccuracyRunStatuses ) : Promise < void > {
6060 const resultFilePath = this . getAccuracyResultFilePath ( commitSHA , runId ) ;
61- let releaseLock : ( ( ) => Promise < void > ) | undefined ;
62- try {
63- releaseLock = await lock ( resultFilePath , { retries : 10 } ) ;
61+ await this . withFileLock ( resultFilePath , async ( ) => {
6462 const accuracyResult = await this . getAccuracyResult ( commitSHA , runId , false ) ;
6563 if ( ! accuracyResult ) {
6664 throw new Error ( "Results not found!" ) ;
@@ -78,23 +76,16 @@ export class DiskBasedResultStorage implements AccuracyResultStorage {
7876 ) ,
7977 { encoding : "utf8" }
8078 ) ;
81- } catch ( error ) {
82- console . warn (
83- `Could not update run status to ${ status } for commit - ${ commitSHA } , runId - ${ runId } .` ,
84- error
85- ) ;
86- throw error ;
87- } finally {
88- await releaseLock ?.( ) ;
89- }
79+ } ) ;
9080
9181 // This bit is important to mark the current run as the latest run for a
9282 // commit so that we can use that during baseline comparison.
9383 if ( status === AccuracyRunStatus . Done ) {
94- await this . atomicUpdateLink (
95- this . getAccuracyResultFilePath ( commitSHA , runId ) ,
96- this . getLatestResultFilePath ( commitSHA )
97- ) ;
84+ const latestResultFilePath = this . getLatestResultFilePath ( commitSHA ) ;
85+ await this . withFileLock ( latestResultFilePath , async ( ) => {
86+ await fs . unlink ( latestResultFilePath ) ;
87+ await fs . link ( resultFilePath , latestResultFilePath ) ;
88+ } ) ;
9889 }
9990 }
10091
@@ -134,50 +125,36 @@ export class DiskBasedResultStorage implements AccuracyResultStorage {
134125 return ;
135126 }
136127
137- let releaseLock : ( ( ) => Promise < void > ) | undefined ;
138- try {
139- releaseLock = await lock ( resultFilePath , { retries : 10 } ) ;
140- const accuracyResult = await this . getAccuracyResult ( commitSHA , runId , false ) ;
128+ await this . withFileLock ( resultFilePath , async ( ) => {
129+ let accuracyResult = await this . getAccuracyResult ( commitSHA , runId , false ) ;
141130 if ( ! accuracyResult ) {
142131 throw new Error ( "Expected at-least initial accuracy result to be present" ) ;
143132 }
144133
145134 const existingPromptIdx = accuracyResult . promptResults . findIndex ( ( result ) => result . prompt === prompt ) ;
146135 const promptResult = accuracyResult . promptResults [ existingPromptIdx ] ;
147- if ( ! promptResult ) {
148- return await fs . writeFile (
149- resultFilePath ,
150- JSON . stringify (
136+ if ( promptResult ) {
137+ accuracyResult . promptResults . splice ( existingPromptIdx , 1 , {
138+ prompt : promptResult . prompt ,
139+ expectedToolCalls : promptResult . expectedToolCalls ,
140+ modelResponses : [ ...promptResult . modelResponses , modelResponse ] ,
141+ } ) ;
142+ } else {
143+ accuracyResult = {
144+ ...accuracyResult ,
145+ promptResults : [
146+ ...accuracyResult . promptResults ,
151147 {
152- ...accuracyResult ,
153- promptResults : [
154- ...accuracyResult . promptResults ,
155- {
156- prompt,
157- expectedToolCalls,
158- modelResponses : [ modelResponse ] ,
159- } ,
160- ] ,
148+ prompt,
149+ expectedToolCalls,
150+ modelResponses : [ modelResponse ] ,
161151 } ,
162- null ,
163- 2
164- )
165- ) ;
152+ ] ,
153+ } ;
166154 }
167155
168- accuracyResult . promptResults . splice ( existingPromptIdx , 1 , {
169- prompt : promptResult . prompt ,
170- expectedToolCalls : promptResult . expectedToolCalls ,
171- modelResponses : [ ...promptResult . modelResponses , modelResponse ] ,
172- } ) ;
173-
174- return await fs . writeFile ( resultFilePath , JSON . stringify ( accuracyResult , null , 2 ) ) ;
175- } catch ( error ) {
176- console . warn ( `Could not save model response for commit - ${ commitSHA } , runId - ${ runId } .` , error ) ;
177- throw error ;
178- } finally {
179- await releaseLock ?.( ) ;
180- }
156+ await fs . writeFile ( resultFilePath , JSON . stringify ( accuracyResult , null , 2 ) ) ;
157+ } ) ;
181158 }
182159
183160 close ( ) : Promise < void > {
@@ -206,20 +183,16 @@ export class DiskBasedResultStorage implements AccuracyResultStorage {
206183 }
207184 }
208185
209- private async atomicUpdateLink ( filePath : string , linkPath : string ) {
210- for ( let attempt = 0 ; attempt < 10 ; attempt ++ ) {
211- try {
212- const tempLinkPath = `${ linkPath } ~${ Date . now ( ) } ` ;
213- await fs . link ( filePath , tempLinkPath ) ;
214- await fs . rename ( tempLinkPath , linkPath ) ;
215- return ;
216- } catch ( error ) {
217- if ( attempt < 10 ) {
218- await this . waitFor ( 100 + Math . random ( ) * 200 ) ;
219- } else {
220- throw error ;
221- }
222- }
186+ private async withFileLock ( filePath : string , callback : ( ) => Promise < void > ) : Promise < void > {
187+ let releaseLock : ( ( ) => Promise < void > ) | undefined ;
188+ try {
189+ releaseLock = await lock ( filePath , { retries : 10 } ) ;
190+ await callback ( ) ;
191+ } catch ( error ) {
192+ console . warn ( `Could not acquire lock for file - ${ filePath } .` , error ) ;
193+ throw error ;
194+ } finally {
195+ await releaseLock ?.( ) ;
223196 }
224197 }
225198
@@ -230,8 +203,4 @@ export class DiskBasedResultStorage implements AccuracyResultStorage {
230203 private getLatestResultFilePath ( commitSHA : string ) : string {
231204 return path . join ( ACCURACY_RESULTS_DIR , commitSHA , `${ LATEST_ACCURACY_RUN_NAME } .json` ) ;
232205 }
233-
234- private waitFor ( ms : number ) {
235- return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
236- }
237206}
0 commit comments