@@ -10,13 +10,38 @@ import type {
1010} from "../../../genesis/besu-genesis.service.ts" ;
1111import {
1212 createKubernetesClient ,
13+ type KubernetesClient ,
1314 readConfigMap ,
1415 toAllocationConfigMapName ,
1516} from "../../integrations/kubernetes/kubernetes.client.ts" ;
1617
1718const GENESIS_DATA_KEY = "genesis.json" ;
1819const ALLOCATION_DATA_KEY = "alloc.json" ;
1920const DEFAULT_OUTPUT_PATH = "/data/atk-genesis.json" ;
21+ const DEFAULT_GENESIS_WAIT_TIMEOUT_MS = 120_000 ;
22+ const DEFAULT_GENESIS_WAIT_INTERVAL_MS = 2000 ;
23+ const MIN_GENESIS_WAIT_INTERVAL_MS = 200 ;
24+ const MILLISECONDS_IN_SECOND = 1000 ;
25+
26+ const parseDuration = ( raw : string | undefined , fallback : number ) : number => {
27+ if ( ! raw ) {
28+ return fallback ;
29+ }
30+ const parsed = Number . parseInt ( raw , 10 ) ;
31+ if ( Number . isFinite ( parsed ) && parsed >= 0 ) {
32+ return parsed ;
33+ }
34+ return fallback ;
35+ } ;
36+
37+ const GENESIS_WAIT_TIMEOUT_MS = parseDuration (
38+ Bun . env . GENESIS_WAIT_TIMEOUT_MS ,
39+ DEFAULT_GENESIS_WAIT_TIMEOUT_MS
40+ ) ;
41+ const GENESIS_WAIT_INTERVAL_MS = parseDuration (
42+ Bun . env . GENESIS_WAIT_INTERVAL_MS ,
43+ DEFAULT_GENESIS_WAIT_INTERVAL_MS
44+ ) ;
2045
2146type CompileGenesisOptions = {
2247 genesisConfigMapName : string ;
@@ -115,17 +140,72 @@ const parseAllocationEntry = (
115140 return parsed ;
116141} ;
117142
143+ const waitForGenesisConfig = async (
144+ context : KubernetesClient ,
145+ name : string
146+ ) => {
147+ const timeout = GENESIS_WAIT_TIMEOUT_MS ;
148+ const interval = Math . max (
149+ GENESIS_WAIT_INTERVAL_MS ,
150+ MIN_GENESIS_WAIT_INTERVAL_MS
151+ ) ;
152+ const start = Date . now ( ) ;
153+ let attempts = 0 ;
154+
155+ while ( attempts === 0 || Date . now ( ) - start < timeout ) {
156+ attempts += 1 ;
157+ const config = await readConfigMap ( context , name ) ;
158+ if ( config ) {
159+ if ( attempts > 1 ) {
160+ const elapsedSeconds = (
161+ ( Date . now ( ) - start ) /
162+ MILLISECONDS_IN_SECOND
163+ ) . toFixed ( 1 ) ;
164+ process . stdout . write (
165+ `ConfigMap ${ name } became available after ${ elapsedSeconds } s (attempt ${ attempts } ).\n`
166+ ) ;
167+ }
168+ return config ;
169+ }
170+
171+ if ( timeout === 0 || Date . now ( ) - start >= timeout ) {
172+ return ;
173+ }
174+
175+ if ( attempts === 1 ) {
176+ const seconds = Math . round ( timeout / MILLISECONDS_IN_SECOND ) ;
177+ process . stdout . write (
178+ `ConfigMap ${ name } not found; waiting up to ${ seconds } s for it to become available.\n`
179+ ) ;
180+ } else {
181+ const delaySeconds = Math . round ( interval / MILLISECONDS_IN_SECOND ) ;
182+ process . stdout . write (
183+ `ConfigMap ${ name } still unavailable; retrying in ${ delaySeconds } s (attempt ${ attempts } ).\n`
184+ ) ;
185+ }
186+
187+ await Bun . sleep ( interval ) ;
188+ }
189+
190+ return ;
191+ } ;
192+
118193const compileGenesis = async ( {
119194 genesisConfigMapName,
120195 outputPath,
121196} : CompileGenesisOptions ) : Promise < void > => {
122197 const context = await createKubernetesClient ( ) ;
123198 const { namespace } = context ;
124199
125- const genesisConfig = await readConfigMap ( context , genesisConfigMapName ) ;
200+ const genesisConfig = await waitForGenesisConfig (
201+ context ,
202+ genesisConfigMapName
203+ ) ;
126204 if ( ! genesisConfig ) {
127205 throw new Error (
128- `ConfigMap ${ genesisConfigMapName } not found in namespace ${ namespace } .`
206+ `ConfigMap ${ genesisConfigMapName } not found in namespace ${ namespace } after waiting up to ${ Math . round (
207+ GENESIS_WAIT_TIMEOUT_MS / MILLISECONDS_IN_SECOND
208+ ) } seconds.`
129209 ) ;
130210 }
131211
0 commit comments