Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EventbridgeToStepfunctions log group name breaks on redeployment #945

Closed
borgoat opened this issue Apr 11, 2023 · 4 comments
Closed

EventbridgeToStepfunctions log group name breaks on redeployment #945

borgoat opened this issue Apr 11, 2023 · 4 comments
Labels
bug Something isn't working needs-triage The issue or PR still needs to be triaged

Comments

@borgoat
Copy link

borgoat commented Apr 11, 2023

Deploying the same Stack twice - with no changes - results in 2 different CloudFormation Templates, breaking CDK determinism.

This becomes a double issue for us since our Stack uses quite some custom resources, meaning our first deployment must happen with --no-rollback, but a second deployment will fail since it's not only retrying the same Stack as before, but also applying an update (which triggers a Replacement type updates not supported on stack with disable-rollback. error)

Reproduction Steps

  1. Define a basic EventbridgeToStepfunctions Construct, letting it generate its own Log Group name.
  2. Deploy a Stack that can fail with no-rollback
  3. Re-deploy the same Stack - now the error will be caused by the Log Group of the State Machine.
import { EventbridgeToStepfunctions } from '@aws-solutions-constructs/aws-eventbridge-stepfunctions';

// [...]

    new EventbridgeToStepfunctions(this, 'DailyGetPriceWorkflow', {
      stateMachineProps: {
        definition: getInstrumentsPricesPath,
      },
      eventRuleProps: {
        schedule: events.Schedule.cron({ hour, minute }),
      },
    });

Error Log

3:50:52 PM | UPDATE_FAILED        | AWS::Logs::LogGroup                       | BookingConstructDa...neLogGroup0B51312C
Replacement type updates not supported on stack with disable-rollback.


 ❌  Prod/Stateles (Prod-Stateles) failed: Error: The stack named Prod-Stateles failed to deploy: UPDATE_FAILED (The following resource(s) failed to update: [BookingConstructDailyInstrumentsPricesLoadDailyGetPriceWorkflowStateMachineLogGroup0B51312C]. ): Replacement type updates not supported on stack with disable-rollback.
    at FullCloudFormationDeployment.monitorDeployment (/yeekatee/node_modules/aws-cdk/lib/index.js:380:10236)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async deployStack2 (/yeekatee/node_modules/aws-cdk/lib/index.js:383:145458)
    at async /yeekatee/node_modules/aws-cdk/lib/index.js:383:128776
    at async run (yeekatee/node_modules/aws-cdk/lib/index.js:383:126782)

 ❌ Deployment failed: Error: Stack Deployments Failed: Error: The stack named Prod-Stateles failed to deploy: UPDATE_FAILED (The following resource(s) failed to update: [BookingConstructDailyInstrumentsPricesLoadDailyGetPriceWorkflowStateMachineLogGroup0B51312C]. ): Replacement type updates not supported on stack with disable-rollback.
    at deployStacks (/yeekatee/node_modules/aws-cdk/lib/index.js:383:129083)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async CdkToolkit.deploy (/yeekatee/node_modules/aws-cdk/lib/index.js:383:147507)
    at async exec4 (/yeekatee/node_modules/aws-cdk/lib/index.js:438:51799)

Stack Deployments Failed: Error: The stack named Prod-Stateles failed to deploy: UPDATE_FAILED (The following resource(s) failed to update: [BookingConstructDailyInstrumentsPricesLoadDailyGetPriceWorkflowStateMachineLogGroup0B51312C]. ): Replacement type updates not supported on stack with disable-rollback.

Environment

  • CDK CLI Version : 2.72.1
  • CDK Framework Version : 2.72.1
  • AWS Solutions Constructs Version : 2.36.0
  • OS : macOS Ventura 13
  • Language : TypeScript 4.9

Other

Before, we had the same problem described in issue #920 - this was fixed in PR #922 in a way that I believe goes against CDK best practices: 1 CDK Stacks should be deterministic, they should (in most cases) not depend on external state, e.g. the current time. Synthesising the same Stack twice (against the same account, with the same code in the repo), should result in the same CloudFormation Template.

My recommendation would be to use CDK Names.uniqueId 2 utility function or construct.node.addr to generate the suffix of the Log Group name, to avoid further issues.


This is 🐛 Bug Report

Footnotes

  1. https://docs.aws.amazon.com/cdk/v2/guide/best-practices.html#best-practices-apps

  2. https://docs.aws.amazon.com/cdk/v2/guide/identifiers.html#identifiers_unique_ids

@borgoat borgoat added bug Something isn't working needs-triage The issue or PR still needs to be triaged labels Apr 11, 2023
@biffgaut
Copy link
Contributor

Thanks - we'll take a look

@biffgaut
Copy link
Contributor

We're looking into this deeper, and consulting with the CDK team. In the meantime you can get around the problem for the time being by specifying the Log Group name in the logGroupProps property of EventbridgeToStepFunctionsProp argument. That overrides any physical log name we would create.

@biffgaut
Copy link
Contributor

What is needed is a name that is constant within the lifetime of the instance of a stack, but different when a new instance of the stack is created. As the CDK code effectively finishes executing before the actual launching of the template, there is no knowledge of the stack instance in any CDK capability. But when the stack launches there is the stack id available in CloudFormation that has the behavior we need - constant in a stack instance, different in two different stack instances. The unique aspect of the Stack ID is easily obtainable from the STACK_ID pseudo parameter. You can use code like this to generate a physical name based on the STACK_ID:

    const uniqueStackIdPart = cdk.Fn.select(2, cdk.Fn.split('/', `${cdk.Aws.STACK_ID}`));
    const instanceSpecificLogGroupName = cdk.Fn.join('-', ['/aws/vendedlogs/states/uniquename', uniqueStackIdPart]);
    // In place of 'uniquename' above you may want to use the CDK UniqueId function or equivalent

    new EventbridgeToStepfunctions(this, 'DailyGetPriceWorkflow', {
      stateMachineProps: {
        definition: startState,
      },
      eventRuleProps: {
        schedule: events.Schedule.rate(cdk.Duration.minutes(15))
      },
      logGroupProps: {
        logGroupName: instanceSpecificLogGroupName
      }
    });

We will be implementing a fix based on the same principle, but in the meantime the code above should allow you to move forward immediately. I believe this also addresses the CDK Determinism concern, as the template will reference AWS::StackId, so the template should be the same for multiple exections.

@biffgaut
Copy link
Contributor

Release 2.39.0 should fix this problem, it include PR #954

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs-triage The issue or PR still needs to be triaged
Projects
None yet
Development

No branches or pull requests

2 participants