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

Circular dependency between resources when using Cognito custom-message and DynamoDB stream together #1723

Closed
jbp35 opened this issue Jul 7, 2024 · 3 comments
Labels
pending-triage Incoming issues that need categorization sandbox Related to the sandbox experience

Comments

@jbp35
Copy link

jbp35 commented Jul 7, 2024

Environment information

System:
  OS: Windows 11 10.0.22631
  CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
  Memory: 1.51 GB / 15.73 GB
Binaries:
  Node: 20.10.0 - C:\Program Files\nodejs\node.EXE
  Yarn: undefined - undefined
  npm: 9.8.1 - C:\Program Files\nodejs\npm.CMD
  pnpm: undefined - undefined
NPM Packages:
  @aws-amplify/backend: 1.0.4
  @aws-amplify/backend-cli: 1.1.0
  aws-amplify: 6.3.8
  aws-cdk: 2.147.2
  aws-cdk-lib: 2.147.2
  typescript: 5.5.2
AWS environment variables:
  AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1
  AWS_SDK_LOAD_CONFIG = 1
  AWS_STS_REGIONAL_ENDPOINTS = regional
No CDK environment variables

Description

What I did:

  1. Configure a function to handle custom messages in Amazon Cognito following this tutorial:
    https://docs.amplify.aws/react/build-a-backend/functions/examples/custom-message/

  2. Add a DynamoDB Stream to sync data from the database to an external service using Lambda in backend.ts:

import { defineBackend } from '@aws-amplify/backend';
import { auth } from './auth/resource';
import { data } from './data/resource';
import {searchEngineSync} from './functions/searchEngineSync/resource';
import { StartingPosition } from "aws-cdk-lib/aws-lambda";
import { DynamoEventSource } from "aws-cdk-lib/aws-lambda-event-sources";

/**
 * @see https://docs.amplify.aws/react/build-a-backend/ to add storage, functions, and more
 */
const backend = defineBackend({
  auth,
  data,
  searchEngineSync
});

// add trigger on dynamodb stream for searchEngineSync lambda function
const eventSource = new DynamoEventSource(backend.data.resources.tables["Layer"], {
  startingPosition: StartingPosition.LATEST,
  retryAttempts:3,
  batchSize:1
});
backend.searchEngineSync.resources.lambda.addEventSource(eventSource);

The error message

The CloudFormation deployment has failed.
Caused By: ❌ Deployment failed: Error [ValidationError]: Circular dependency between resources: [auth179371D7, data7552DF31, function1351588B]
Resolution: Find more information in the CloudFormation AWS Console for this stack.

Similar issues

I found similar issue which seems to have been solved but the solution is not very clear:
#1552

@jbp35 jbp35 added the pending-triage Incoming issues that need categorization label Jul 7, 2024
@ykethan
Copy link
Member

ykethan commented Jul 9, 2024

Hey @jbp35, thank you for reaching out. Issue occurs as there a circular dependancy between the resources, auth -> function -> data -> auth. Refer to this post providing additional information on this: https://aws.amazon.com/blogs/infrastructure-and-automation/handling-circular-dependency-errors-in-aws-cloudformation/

Similar to the issue linked we will need to break the circular dependancy

import { Stack } from "aws-cdk-lib";
import { EventSourceMapping, StartingPosition } from "aws-cdk-lib/aws-lambda";
import { Effect, Policy, PolicyStatement } from "aws-cdk-lib/aws-iam";
import { myFunction } from "./functions/my-function/resource";

const backend = defineBackend({
  auth,
  data,
  myFunction,
});

const todoTable = backend.data.resources.tables["Todo"];
const tableStreamArn = todoTable.tableStreamArn || "";

// adds the policy to the table stack
const newPolicy = new Policy(Stack.of(todoTable), "DynamoDBPolicy", {
  statements: [
    new PolicyStatement({
      effect: Effect.ALLOW,
      actions: [
        "dynamodb:DescribeStream",
        "dynamodb:GetRecords",
        "dynamodb:GetShardIterator",
        "dynamodb:ListStreams",
      ],
      resources: [tableStreamArn],
    }),
  ],
});

// attach policy to lambda role
const lambdaRole = backend.myFunction.resources.lambda.role;
lambdaRole.attachInlinePolicy(newPolicy);

// create the stream trigger on the lambda 
const eventSourceMapping = new EventSourceMapping(
  Stack.of(todoTable),
  "DynamoDBSource",
  {
    eventSourceArn: tableStreamArn,
    startingPosition: StartingPosition.LATEST,
    batchSize: 1,
    target: backend.myFunction.resources.lambda,
    retryAttempts: 3,
  }
);

// adds a dependancy to prevent a race condition
eventSourceMapping.node.addDependency(newPolicy);

@ykethan ykethan added sandbox Related to the sandbox experience pending-response Issue is pending response from author labels Jul 9, 2024
@jbp35
Copy link
Author

jbp35 commented Jul 9, 2024

Thank you for the code example. This is working.

@github-actions github-actions bot removed the pending-response Issue is pending response from author label Jul 9, 2024
@ykethan
Copy link
Member

ykethan commented Jul 9, 2024

Closing the issue. Do reach out if you require any assistance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pending-triage Incoming issues that need categorization sandbox Related to the sandbox experience
Projects
None yet
Development

No branches or pull requests

2 participants