@@ -11,14 +11,33 @@ async function waitForFile(filePath: string): Promise<void> {
1111 throw new Error ( `Timed out waiting for ${ filePath } ` ) ;
1212}
1313
14+ async function waitForFetchCount (
15+ filePath : string ,
16+ minimum : number ,
17+ ) : Promise < number > {
18+ for ( let attempt = 0 ; attempt < 200 ; attempt += 1 ) {
19+ if ( await Bun . file ( filePath ) . exists ( ) ) {
20+ const count = Number ( await Bun . file ( filePath ) . text ( ) ) ;
21+ if ( count >= minimum ) {
22+ return count ;
23+ }
24+ }
25+ await Bun . sleep ( 10 ) ;
26+ }
27+ throw new Error ( `Timed out waiting for ${ minimum } fetches in ${ filePath } ` ) ;
28+ }
29+
1430async function runShutdownCase ( exchangeCloseHangs : boolean ) : Promise < {
1531 exitCode : number ;
1632 closeMarker : string ;
33+ countBeforeShutdown : number ;
34+ countAtShutdown : number ;
1735 output : string ;
1836} > {
1937 const fixtureId = crypto . randomUUID ( ) ;
2038 const configPath = `/tmp/ohlcv-shutdown-${ fixtureId } .json` ;
2139 const activePath = `/tmp/ohlcv-shutdown-${ fixtureId } .active` ;
40+ const countPath = `/tmp/ohlcv-shutdown-${ fixtureId } .count` ;
2241 const closedPath = `/tmp/ohlcv-shutdown-${ fixtureId } .closed` ;
2342 await Bun . write (
2443 configPath ,
@@ -38,6 +57,7 @@ async function runShutdownCase(exchangeCloseHangs: boolean): Promise<{
3857 CEX_BROKER_OHLCV_COLLECTOR_CONFIG : configPath ,
3958 CEX_BROKER_OHLCV_ARCHIVE_BOOTSTRAP_LIMIT : "0" ,
4059 OHLCV_TEST_EXCHANGE_ACTIVE_PATH : activePath ,
60+ OHLCV_TEST_EXCHANGE_COUNT_PATH : countPath ,
4161 OHLCV_TEST_EXCHANGE_CLOSED_PATH : closedPath ,
4262 OHLCV_TEST_EXCHANGE_CLOSE_HANG : String ( exchangeCloseHangs ) ,
4363 } ,
@@ -49,6 +69,14 @@ async function runShutdownCase(exchangeCloseHangs: boolean): Promise<{
4969
5070 try {
5171 await waitForFile ( activePath ) ;
72+ const countBeforeShutdown = await waitForFetchCount ( countPath , 5 ) ;
73+ expect ( await Bun . file ( closedPath ) . exists ( ) ) . toBe ( false ) ;
74+ await Bun . sleep ( 100 ) ;
75+ const countAtShutdown = await waitForFetchCount (
76+ countPath ,
77+ countBeforeShutdown + 1 ,
78+ ) ;
79+ expect ( await Bun . file ( closedPath ) . exists ( ) ) . toBe ( false ) ;
5280 child . kill ( "SIGTERM" ) ;
5381 const result = await Promise . race ( [
5482 child . exited . then ( ( exitCode ) => ( { exitCode } ) ) ,
@@ -64,6 +92,8 @@ async function runShutdownCase(exchangeCloseHangs: boolean): Promise<{
6492 return {
6593 exitCode : result . exitCode ,
6694 closeMarker : await Bun . file ( closedPath ) . text ( ) ,
95+ countBeforeShutdown,
96+ countAtShutdown,
6797 output : `${ await stdout } \n${ await stderr } ` ,
6898 } ;
6999 } finally {
@@ -72,7 +102,7 @@ async function runShutdownCase(exchangeCloseHangs: boolean): Promise<{
72102 await child . exited ;
73103 }
74104 await Promise . all (
75- [ configPath , activePath , closedPath ] . map ( async ( filePath ) => {
105+ [ configPath , activePath , countPath , closedPath ] . map ( async ( filePath ) => {
76106 if ( await Bun . file ( filePath ) . exists ( ) ) {
77107 await Bun . file ( filePath ) . delete ( ) ;
78108 }
@@ -85,6 +115,7 @@ test("entrypoint exits promptly on SIGTERM after an exchange stream opens", asyn
85115 const result = await runShutdownCase ( false ) ;
86116 expect ( result . exitCode ) . toBe ( 0 ) ;
87117 expect ( result . closeMarker ) . toBe ( "closed" ) ;
118+ expect ( result . countAtShutdown ) . toBeGreaterThan ( result . countBeforeShutdown ) ;
88119} ) ;
89120
90121test ( "entrypoint bounds shutdown when an exchange close does not resolve" , async ( ) => {
0 commit comments