aws / jsii

jsii allows code in any language to naturally interact with JavaScript classes. It is the technology that enables the AWS Cloud Development Kit to deliver polyglot libraries from a single codebase!
https://aws.github.io/jsii
Apache License 2.0
2.65k stars 245 forks source link

Golang CDK: synth fails when using lazy string due to circular reference #4486

Open tdenniston opened 6 months ago

tdenniston commented 6 months ago

Describe the bug

This is probably specific to the Go CDK bindings, or it is also possible I am misunderstanding the use of the lazy string mechanism. When I try to use the awscdk.Lazy_String method for e.g. a log group name, synth fails due to a circular reference:

$ CDK_DEBUG=true cdk synth
panic: TypeError: Resolution error: Resolution error: Resolution error: Converting circular structure to JSON
    --> starting at object with constructor 'CfnLogGroup'
    |     property 'node' -> object with constructor 'Node'
    --- property 'host' closes the circle.
Object creation stack:
  at Lazy.string (/tmp/jsii-kernel-u0LhzS/node_modules/aws-cdk-lib/core/lib/lazy.js:1:953)
  at /tmp/jsii-runtime.3237986321/lib/program.js:9876:152
  at Kernel._Kernel_ensureSync (/tmp/jsii-runtime.3237986321/lib/program.js:10480:24)
  at Kernel.sinvoke (/tmp/jsii-runtime.3237986321/lib/program.js:9876:102)
  at KernelHost.processRequest (/tmp/jsii-runtime.3237986321/lib/program.js:11696:36)
  at KernelHost.run (/tmp/jsii-runtime.3237986321/lib/program.js:11656:22)
  at Immediate._onImmediate (/tmp/jsii-runtime.3237986321/lib/program.js:11657:46)
  at process.processImmediate (node:internal/timers:476:21)..

See below for a very simple example that reproduces the issue.

Expected Behavior

Able to use the awscdk.Lazy_String function.

Current Behavior

Synth fails when using the awscdk.Lazy_String function.

Reproduction Steps

Complete example:

package main

import (
    "github.com/aws/aws-cdk-go/awscdk/v2"
    "github.com/aws/aws-cdk-go/awscdk/v2/awslogs"

    "github.com/aws/jsii-runtime-go"
)

type LazyString struct{}

func (l *LazyString) Produce() *string {
    s := "value"
    return &s
}

func main() {
    defer jsii.Close()

    app := awscdk.NewApp(nil)
    stack := awscdk.NewStack(app, jsii.String("stack"), &awscdk.StackProps{})

    lazy := &LazyString{}
    awslogs.NewLogGroup(stack, jsii.String("log-group"), &awslogs.LogGroupProps{
        LogGroupName: awscdk.Lazy_String(lazy, &awscdk.LazyStringValueOptions{}),
    })

    app.Synth(nil)
}

Then just run cdk synth, and it will fail.

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.137.0 (build bb90b4c)

Framework Version

No response

Node.js Version

18.18.2

OS

Linux

Language

Go

Language Version

go version go1.20.12 linux/amd64

Other information

No response

ashishdhingra commented 6 months ago

Reproducible.

teemu-laakso commented 5 months ago

I hit this bug with python and found a workaround. Taking the example from the CDK Guide:

class Producer:
    def __init__(self, func):
        self.produce = func
class FixedProducer:
    __jsii_type__ = None

    def __init__(self, func):
        self.func = func

    @jsii.member(jsii_name='produce')
    def produce(self, context):
        return self.func()

Maybe this can be of some use with Go as well?

floverfelt commented 2 weeks ago

Also an issue in Java:

package com.myorg;

import software.amazon.awscdk.IStableStringProducer;
import software.amazon.awscdk.Lazy;
import software.amazon.awscdk.services.sqs.Queue;
import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;

public class CdkBugTestStack extends Stack {

    public CdkBugTestStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public class LazyStableString implements IStableStringProducer {
        @Override
        public String produce() {
            return "LazyStableCDKBugTestQueue";
        }
    }

    public CdkBugTestStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);
         Queue.Builder.create(this, "CdkBugTestQueue")
                 .queueName(Lazy.string(new LazyStableString()))
                 .build();
    }
}

produces:

An exception occurred while executing the Java class. TypeError: Resolution error: Resolution error: Resolution error: Converting circular structure to JSON
    --> starting at object with constructor 'CfnQueue'
    |     property 'node' -> object with constructor 'Node'
    --- property 'host' closes the circle.

Switching to uncachedString works fine: https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Lazy.html#static-uncachedwbrstringproducer-options

But this seems to be discouraged by the docs.