Contexto, tengo una aplicación CDK con dos pilas usando la siguiente configuración:
Stack_A: StateMachine_A Lambda_A S3Bucket_A IAMRole_A Stack_B: StateMachine_B SageMakerTrainJob_B IAMRole_BStateMachine_A ejecuta Lambda_A mediante el rol de ejecución IAMRole_A. Un paso separado en StateMachine_A escribe datos en S3Bucket_A. StateMachine_B ejecuta SageMakerTrainJob_B mediante el rol de ejecución IAMRole_B. El propósito de Lambda_A es iniciar la ejecución de StateMachine_B, cuyo SageMakerTrainJob_B necesita leer desde S3Bucket_A. Por lo tanto, tenemos que configurar los siguientes permisos:
Intentamos modelar esto en CDK creando una dependencia directa en Stack_B en Stack_A, usando referencias a IAMRole_A y S3Bucket_A dentro de la definición de Stack_B para otorgar los permisos necesarios en el código. Sin embargo, esto generó el siguiente error:
Error: 'Stack_B' depends on 'Stack_A' (dependency added using stack.addDependency()). Adding this dependency (Stack_A -> Stack_B/IAMRole_B/Resource.Arn) would create a cyclic reference.
Del mismo modo, tratar de modelar la dependencia en la otra dirección dio el mismo error:
Error: 'Stack_A' depends on 'Stack_B' (dependency added using stack.addDependency()). Adding this dependency (Stack_B -> Stack_A/S3Bucket_A/Resource.Arn) would create a cyclic reference.
¿Hay alguna forma de evitar esto usando dependencias de código? ¿Existen mejores prácticas recomendadas para situaciones como esta? Algunas opciones que hemos considerado incluyen:
Además, veo que hubo problemas similares durante el desarrollo de CDK con CodeCommit/CodePipeline y APIGateway/Lambda . ¿Se trata de un error relacionado o simplemente estamos tratando de hacer algo que no es compatible?
Las referencias circulares siempre son complicadas. Este no es un problema exclusivo del CDK. A medida que explica el problema lógicamente, ve dónde las cosas comienzan a descomponerse. CloudFormation debe crear cualquier recurso del que dependa otro recurso antes de poder crear el recurso dependiente. No hay una solución que se ajuste a todos los enfoques para esto, pero daré algunas ideas que funcionan.
Además de las pautas de Jason, me gustaría mencionar una cuarta opción:
También puede intentar desacoplar las dos pilas moviéndose más hacia una arquitectura basada en eventos. Si bien no puede resolver la dependencia de IAMRole_B needs read permissions on S3Bucket_A en este ejemplo, puede resolver la dependencia IAMRole_A needs startExecution permissions on StateMachine_B . La pila A podría presentar un EventBridge donde StateMachine_A genera un evento tan pronto como finaliza. StateMachine_B puede suscribirse a este evento y comenzar tan pronto como se haya generado. Las pilas se verían así:
Stack_A: StateMachine_A Event_A S3Bucket_A IAMRole_A Stack_B: StateMachine_B SageMakerTrainJob_B IAMRole_BTodavía tendrías dos dependencias: