-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
[appmesh] VirtualNode in separate stack from Mesh creates circular dependency #10049
Comments
I was able to reproduce the error. Although I am still investing the root cause, I was able to avoid the error by creating the For sample code. please refer https://github.com/Seiya6329/appmesh-cross-stack-bug/tree/wayaround Next step: |
Minimal reproduction: import * as cdk from '@aws-cdk/core';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as ecs from '@aws-cdk/aws-ecs';
import * as appmesh from '@aws-cdk/aws-appmesh';
export class MeshStack extends cdk.Stack {
public readonly cluster: ecs.Cluster;
public readonly mesh: appmesh.Mesh;
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const vpc = new ec2.Vpc(this, 'Vpc');
this.cluster = new ecs.Cluster(this, 'Cluster', {
vpc: vpc,
defaultCloudMapNamespace: {
name: 'cdkbug.local',
},
});
this.mesh = new appmesh.Mesh(this, 'Mesh');
}
}
interface ServiceStackProps extends cdk.StackProps {
readonly cluster: ecs.ICluster,
readonly mesh: appmesh.IMesh,
}
export class ServiceStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props: ServiceStackProps) {
super(scope, id, props);
const taskDef = new ecs.FargateTaskDefinition(this, 'TaskDef');
const appContainer = taskDef.addContainer('echo', {
image: ecs.ContainerImage.fromRegistry('hashicorp/http-echo'),
});
appContainer.addPortMappings({ containerPort: 5678 });
const service = new ecs.FargateService(this, "service", {
cluster: props.cluster,
taskDefinition: taskDef,
cloudMapOptions: {}, // empty is fine for reproducing this bug
});
const virtualNode = props.mesh.addVirtualNode('vn', {
/* ******** uncomment below 3 lines to reproduce the error ******** */
// serviceDiscovery: appmesh.ServiceDiscovery.cloudMap({
// service: service.cloudMapService!,
// }),
listeners: [appmesh.VirtualNodeListener.http({
port: appContainer.containerPort,
})],
});
// this also doesn't work:
// const virtualNode2 = new appmesh.VirtualNode(this, 'vn2', {
// mesh: props.mesh,
// });
// this works fine:
const virtualRouter = props.mesh.addVirtualRouter('vr', {
listeners: [appmesh.VirtualRouterListener.http(appContainer.containerPort)],
});
// this works fine too:
const defaultRoute = virtualRouter.addRoute('vr-route-default', {
routeSpec: appmesh.RouteSpec.http({
weightedTargets: [{
virtualNode: virtualNode,
weight: 100,
}],
}),
});
}
}
const app = new cdk.App();
const meshStack = new MeshStack(app, 'MeshStack');
new ServiceStack(app, 'ServiceStack', {
cluster: meshStack.cluster,
mesh: meshStack.mesh,
}); |
The fact this also causes the cycle to happen: const virtualNode2 = new appmesh.VirtualNode(this, 'vn2', {
mesh: props.mesh,
}); worries me a little bit. |
Thanks @skinny85 for pasting the minimal reproduction sample code here. Just to highlight the root cause,
|
I believe the concern is what would be the probability for a user to face this issue. Essentially there are two high-level scenarios to reproduce this error. To simplify, I will refer Scenario 1: Uses a method to create a resource
Scenario 2: Uses a mixture of method and constructor to create a resource
Note: I am pretty sure Scenario #2 can be reproduced using I can imagine a user uses Scenario 1 setup. For example, create For Scenario 2 (same one as @skinny85 is having a slight concern), I am actually not worried too much here. To achieve this scenario, user must use both method and constructors to create resources and although it is definitely possible, it is less consistent to write a code this way. Bottom Line:
@dfezzie and @alexbrjo - Please feel free to share your thoughts here. |
I think I agree with your conclusions @Seiya6329. Looks like I was worried about that This looks to be just a matter of various references between CDK constructs causing dependencies between Stacks. I don't think there's anything unusual here for AppMesh. For the problem posted originally in the issue, it's just a matter of changing from: const virtualNode = props.mesh.addVirtualNode('vn', {
serviceDiscovery: appmesh.ServiceDiscovery.cloudMap({
service: service.cloudMapService!,
}),
listeners: [appmesh.VirtualNodeListener.http({
port: appContainer.containerPort,
})],
}); to: const virtualNode = new appmesh.VirtualNode(this, 'vn', {
mesh: props.mesh,
serviceDiscovery: appmesh.ServiceDiscovery.cloudMap({
service: service.cloudMapService!,
}),
listeners: [appmesh.VirtualNodeListener.http({
port: appContainer.containerPort,
})],
}); to solve the cycle. I think the only possible action from this might be adding some clarification to the documentation of the various |
This is really great point and has been suggested by @dfezzie as well. Conclusion:
|
ETA for updating the documentation: 7/1/21 |
…od to create a resource (#15237) This closes #10049. #### REV - Updating the doc for`.add...()` methods to specify that the resource is created in same stack where the `Mesh` exists - Updating `README` file to clarify the difference between using the constructor and method to create a resource. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
|
…od to create a resource (aws#15237) This closes aws#10049. #### REV - Updating the doc for`.add...()` methods to specify that the resource is created in same stack where the `Mesh` exists - Updating `README` file to clarify the difference between using the constructor and method to create a resource. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Adding a VirtualNode to a Mesh (where the Mesh is in one stack and the VirtualNode is in another) creates an circular reference, but shouldn't.
Reproduction Steps
Sample code available at buzzsurfr/appmesh-cross-stack-bug
Sample code in master branch works, but uncommenting the following lines...
https://github.com/buzzsurfr/appmesh-cross-stack-bug/blob/e374561e516c328ed90de2add287b2d81153a642/lib/meshed-service-stack.ts#L103-L112
...then run:
What did you expect to happen?
This shouldn't be a circular reference and should work.
What actually happened?
Environment
Other
This is 🐛 Bug Report
The text was updated successfully, but these errors were encountered: