@@ -45,6 +45,10 @@ const MANIFEST_DIRS = [
4545
4646const WORKFLOWS = [ "greeting" , "failswitch" ] ;
4747
48+ /** Default SonataFlow operator Postgres secret; e2e uses `backstage-psql-secret` instead. */
49+ const UPSTREAM_WORKFLOW_PG_SECRET = "sonataflow-psql-postgresql" ;
50+ const E2E_WORKFLOW_PG_SECRET = "backstage-psql-secret" ;
51+
4852// ---------------------------------------------------------------------------
4953// RBAC helpers
5054// ---------------------------------------------------------------------------
@@ -399,8 +403,18 @@ export async function deploySonataflow(namespace: string): Promise<void> {
399403 patchWorkflowPostgres ( namespace , workflow ) ;
400404 }
401405
406+ const postgresAlignTimeoutMs = 120_000 ;
402407 for ( const workflow of WORKFLOWS ) {
403- await waitForReconciliation ( namespace , workflow , 60 ) ;
408+ await waitForWorkflowPostgresDeploymentAligned (
409+ namespace ,
410+ workflow ,
411+ postgresAlignTimeoutMs ,
412+ ) ;
413+ runOc (
414+ [ "rollout" , "restart" , `deployment/${ workflow } ` , "-n" , namespace ] ,
415+ 60_000 ,
416+ ) ;
417+ await sleep ( 2_000 ) ;
404418 runOc (
405419 [
406420 "rollout" ,
@@ -447,57 +461,89 @@ function patchWorkflowPostgres(namespace: string, workflow: string): string {
447461 ] ) ;
448462}
449463
450- async function waitForCRs ( namespace : string ) : Promise < void > {
451- const deadline = Date . now ( ) + 60_000 ;
464+ function parseOcJson < T = unknown > (
465+ args : string [ ] ,
466+ timeoutMs : number ,
467+ ) : T | undefined {
468+ try {
469+ return JSON . parse ( runOc ( args , timeoutMs ) ) as T ;
470+ } catch {
471+ return undefined ;
472+ }
473+ }
474+
475+ function sonataFlowUsesE2ePostgresSecret ( cr : Record < string , unknown > ) : boolean {
476+ const spec = cr . spec as Record < string , unknown > | undefined ;
477+ const persistence = spec ?. persistence as Record < string , unknown > | undefined ;
478+ const pg = persistence ?. postgresql as Record < string , unknown > | undefined ;
479+ const secretRef = pg ?. secretRef as Record < string , unknown > | undefined ;
480+ return secretRef ?. name === E2E_WORKFLOW_PG_SECRET ;
481+ }
482+
483+ /** True if the live Deployment pod template still references the operator default secret. */
484+ function deploymentPodTemplateReferencesUpstreamPgSecret (
485+ deployment : Record < string , unknown > ,
486+ ) : boolean {
487+ const spec = deployment . spec as Record < string , unknown > | undefined ;
488+ const template = spec ?. template as Record < string , unknown > | undefined ;
489+ if ( ! template ) return false ;
490+ return JSON . stringify ( template ) . includes ( UPSTREAM_WORKFLOW_PG_SECRET ) ;
491+ }
492+
493+ /**
494+ * Wait until the SonataFlow CR and workflow Deployment both reflect the e2e Postgres
495+ * wiring, re-applying the merge patch when the operator lags. Does not restart the rollout.
496+ */
497+ async function waitForWorkflowPostgresDeploymentAligned (
498+ namespace : string ,
499+ workflow : string ,
500+ timeoutMs : number ,
501+ ) : Promise < void > {
502+ const deadline = Date . now ( ) + timeoutMs ;
452503 let attempt = 0 ;
453504 while ( Date . now ( ) < deadline ) {
454505 attempt ++ ;
455- try {
456- const out = runOc ( [ "get" , "sonataflow" , "-n" , namespace , "--no-headers" ] ) ;
457- const found = out . split ( "\n" ) . filter ( Boolean ) . length ;
458- if ( found >= WORKFLOWS . length ) {
459- return ;
460- }
461- } catch {
462- // not available yet
506+ const cr = parseOcJson < Record < string , unknown > > (
507+ [ "get" , "sonataflow" , workflow , "-n" , namespace , "-o" , "json" ] ,
508+ 15_000 ,
509+ ) ;
510+ const deployment = parseOcJson < Record < string , unknown > > (
511+ [ "get" , "deployment" , workflow , "-n" , namespace , "-o" , "json" ] ,
512+ 15_000 ,
513+ ) ;
514+ const crOk = cr && sonataFlowUsesE2ePostgresSecret ( cr ) ;
515+ const depOk =
516+ deployment &&
517+ ! deploymentPodTemplateReferencesUpstreamPgSecret ( deployment ) ;
518+ if ( crOk && depOk ) {
519+ return ;
463520 }
464- await sleep ( 5_000 ) ;
521+ patchWorkflowPostgres ( namespace , workflow ) ;
522+ await sleep ( 2_000 ) ;
465523 }
466524 console . warn (
467- `[deploy-sonataflow] TIMEOUT: Only found fewer than ${ WORKFLOWS . length } SonataFlow CRs after ${ attempt } attempts ` ,
525+ `[deploy-sonataflow] TIMEOUT ( ${ timeoutMs } ms): workflow " ${ workflow } " not aligned on ${ E2E_WORKFLOW_PG_SECRET } ( SonataFlow CR + Deployment template; attempts= ${ attempt } ) ` ,
468526 ) ;
469527}
470528
471- async function waitForReconciliation (
472- namespace : string ,
473- workflow : string ,
474- timeoutSecs : number ,
475- ) : Promise < void > {
476- const deadline = Date . now ( ) + timeoutSecs * 1_000 ;
529+ async function waitForCRs ( namespace : string ) : Promise < void > {
530+ const deadline = Date . now ( ) + 60_000 ;
477531 let attempt = 0 ;
478532 while ( Date . now ( ) < deadline ) {
479533 attempt ++ ;
480534 try {
481- const status = runOc ( [
482- "get" ,
483- "deployment" ,
484- workflow ,
485- "-n" ,
486- namespace ,
487- "-o" ,
488- 'jsonpath={.status.conditions[?(@.type=="Progressing")].status}' ,
489- ] ) ;
490- const cleaned = status . replaceAll ( "'" , "" ) ;
491- if ( cleaned === "True" ) {
535+ const out = runOc ( [ "get" , "sonataflow" , "-n" , namespace , "--no-headers" ] ) ;
536+ const found = out . split ( "\n" ) . filter ( Boolean ) . length ;
537+ if ( found >= WORKFLOWS . length ) {
492538 return ;
493539 }
494540 } catch {
495541 // not available yet
496542 }
497- await sleep ( 2_000 ) ;
543+ await sleep ( 5_000 ) ;
498544 }
499545 console . warn (
500- `[deploy-sonataflow] TIMEOUT waiting for reconciliation of ${ workflow } after ${ timeoutSecs } s ( ${ attempt } attempts) ` ,
546+ `[deploy-sonataflow] TIMEOUT: Only found fewer than ${ WORKFLOWS . length } SonataFlow CRs after ${ attempt } attempts` ,
501547 ) ;
502548}
503549
0 commit comments