avisi-cloud/structurizr-site-generatr

Loop "Generating side.." triggered by "Detected a change in /var/model/.preview/master/..."

Closed this issue · 6 comments

scope

Thank you for making this tooling available, love it!
I run it in serve mode, here is my docker command:

docker run -it --rm --user root -p 8080:8080 -v $(pwd):/var/model -v $(pwd)/.preview:/build -v $(pwd)/static-assets:/static-assets ghcr.io/avisi-cloud/structurizr-site-generatr serve -w workspace.dsl -s /build -a /static-assets

issue

Once I've saved a change for my workspace.dsl it doesn't stop re-generating the page.
The trigger is logged /var/model/.preview/master/... Snippet from the log, where at the end it just starts all over again, but with different site

Detected a change in /var/model/.preview/master/my-source-systems, updating site...
..
Generating index page...
Copying assets...
Generating diagrams...
Component-010 UP-TO-DATE
...
Generating site...
Successfully generated diagrams and site in 5.773 seconds

Detected a change in /var/model/.preview/master/github-org:-foobar/sections, updating site...
Feb 22, 2024 10:35:49 AM com.structurizr.view.ViewSet generateViewKey

I've not found an option to deactivate the automatic rebuild (only #84 and #42)
Is it only for me, as no one else opened an issue about it?

Thanks for the tooling and you help!

context

My workspace.dsl is using this auto-generate view section

    views {

        theme default

        // https://github.com/avisi-cloud/structurizr-site-generatr/issues/324#issuecomment-1775245588
        !script groovy {
            workspace.views.createDefaultViews()
        }
        systemlandscape "SystemLandscape" {
            include *
            autoLayout
        }

        // copy/pasted to get styled icons working
        // https://github.com/avisi-cloud/structurizr-site-generatr/blob/main/docs/example/workspace.dsl#L163C1-L188C10
        properties {
            "c4plantuml.elementProperties" "true"
            "c4plantuml.tags" "true"
            "generatr.style.colors.primary" "#485fc7"
            "generatr.style.colors.secondary" "#ffffff"
            "generatr.style.faviconPath" "site/favicon.ico"
            "generatr.style.logoPath" "site/logo.png"

            // Absolute URL's like "https://example.com/custom.css" are also supported
            "generatr.style.customStylesheet" "site/custom.css"

            "generatr.svglink.target" "_self"

            // Full list of available "generatr.markdown.flexmark.extensions"
            // "Abbreviation,Admonition,AnchorLink,Aside,Attributes,Autolink,Definition,Emoji,EnumeratedReference,Footnotes,GfmIssues,GfmStrikethroughSubscript,GfmTaskList,GfmUsers,GitLab,Ins,Macros,MediaTags,ResizableImage,Superscript,Tables,TableOfContents,SimulatedTableOfContents,Typographic,WikiLinks,XWikiMacro,YAMLFrontMatter,YouTubeLink"
            // see https://github.com/vsch/flexmark-java/wiki/Extensions
            // ATTENTION:
            // * "generatr.markdown.flexmark.extensions" values must be separated by comma
            // * it's not possible to use "GitLab" and "ResizableImage" extensions together
            // default behaviour, if no generatr.markdown.flexmark.extensions property is specified, is to load the Tables extension only
            "generatr.markdown.flexmark.extensions" "Abbreviation,Admonition,AnchorLink,Attributes,Autolink,Definition,Emoji,Footnotes,GfmTaskList,GitLab,MediaTags,Tables,TableOfContents,Typographic"

            "generatr.site.exporter" "c4"
            "generatr.site.externalTag" "External System"
            "generatr.site.nestGroups" "false"
        }
}

Thanks for the report. I've put your view configuration into the example workspace and run serve locally (from IntelliJ) with master. There I couldn't reproduce the behavior you are describing. Do you have a chance to test with the example workspace with your view configuration inside and outside of docker to narrow this down?

I had the same issue, for some reason it was stuck in an infinite loop due to detecting changes in its own build directoy.
I looked into the code and found this:

.filter { it.isDirectory() && !it.isHidden() && !it.absolutePathString().startsWith(absoluteSiteDir) }

It should filter out the build/serve directory. but upon looking at my logs I noticed that the directory that was logged contains a dot: Detected a change in <project-dir>/./build/master/software-systems, updating site...

I then noticed i ran my command with the workspace file as a relative file path: structurizr-site-generatr serve -w ./workspace.dsl
So i figured that there was something wrong with the path resolution. it wasn't removing the ./ from the absolute path and this, the build directory wasn't being excluded.
Sure enought removing ./ from the -w flag fixed the issue.

Seems like this row:

val path = File(workspaceFile).absoluteFile.parentFile.toPath()

Is getting the parent directory path with the .

Not really sure if this is the same issue as i was having because there is no ./ in the specified issue, but this is my own 2 cents.

@jp7677 need your help with the docker run .. serve .. command to render the docs/example/workspace.dsl

notes about my system:

  • Java 21.0.1
  • Docker version 25.0.4
  • Ubuntu 22.04.4 LTS running in WSL2

I've checked out this repo, cd into docs/example and having a hard time to figure out how to mount the folders and align the -a parameter. Expect it to be way simpler than this:

> docker run -it --rm --user root -p 8082:8080 -v $(pwd):/var/model -v $(pwd)/.preview:/build -v $(pwd)/internet-banking-system:/internet-banking-system -v $(pwd)/atm:/atm -v $(pwd)/workspace-adrs:/workspace-adrs -v $(pwd)/assets:/assets  ghcr.io/avisi-cloud/structurizr-site-generatr serve -w workspace.dsl

Maybe adding it to the docs how to do this with docker for the generate-site and serve could be helpful for others too? :)

Running it fails with recursive(?) file-names like this (check the line where build/master repeats like 100x):

Exception in thread "main" java.io.UncheckedIOException: java.nio.file.FileSystemException: /var/model/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master
.. skipped..build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/build/master/internet-banking-system/api-application/adr/0001-record-architecture-decisions.md: File name too long
        at java.base/java.nio.file.FileTreeIterator.fetchNextIfNeeded(Unknown Source)
        at java.base/java.nio.file.FileTreeIterator.hasNext(Unknown Source)
        at java.base/java.util.Iterator.forEachRemaining(Unknown Source)
        at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Unknown Source)
        at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
        at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
        at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
        at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
        at java.base/java.util.stream.ReferencePipeline.forEach(Unknown Source)
        at nl.avisi.structurizr.site.generatr.ServeCommand.startWatchService(ServeCommand.kt:148)
        at nl.avisi.structurizr.site.generatr.ServeCommand.execute(ServeCommand.kt:55)
        at kotlinx.cli.ArgParser.parse(ArgParser.kt:657)
        at kotlinx.cli.ArgParser.parse(ArgParser.kt:530)
        at nl.avisi.structurizr.site.generatr.AppKt.main(App.kt:13)

@spex66 I've used this command for starting in serve mode after cd'ing into the docs folder of the repository:

docker run -it --rm --user root -p 8080:8080 -v $(pwd)/example:/var/example ghcr.io/avisi-cloud/structurizr-site-generatr serve -w /var/example/workspace.dsl -a /var/example/assets -s /var/build

I've kept the generated folder (build) inside the container and also outside of the mapped example folder. Hot-reload when changing files from my workstation worked as intended. This is on a real Ubuntu 22.04 workstation.

Does a setup like this works for you?

@jp7677 I can confirm that your serve didn't loop!

And I was -- most likely -- able to reproduce the issue now (but cannot explain :):

  • Created a build folder in your docs/example (as I need it for deployment)
    • added to your command line an additional -v $(pwd)/example/build:/build
    • and using the additional mount in -s /build
      That triggers now a loop for me on an updates.
docker run -it --rm --user root -p 8080:8080 -v $(pwd)/example:/var/example -v $(pwd)/example/build:/build ghcr.io/avisi-cloud/structurizr-site-generatr serve -w /var/example/workspace.dsl -a /var/example/assets -s /build

Reason: Like in my case I've mounted $(pwd)/example/build from within the first mounted $(pwd)/example

  • which is not even necessary as I can do it without the second volume-mount but instead -s /var/example/build

Full working command-line which is providing me access to build in docs/example/build folder without looping

docker run -it --rm --user root -p 8080:8080 -v $(pwd)/example:/var/example ghcr.io/avisi-cloud/structurizr-site-generatr serve -w /var/example/workspace.dsl -a /var/example/assets -s /var/example/build

Finally proofed with my workspace:

  • Fixing my original posted commandline (check the -s and removed second -v)
# looping
docker run -it --rm --user root -p 8080:8080 -v $(pwd):/var/model -v $(pwd)/.preview:/build -v $(pwd)/static-assets:/static-assets ghcr.io/avisi-cloud/structurizr-site-generatr serve -w workspace.dsl -s /build -a /static-assets

# not looping
docker run -it --rm --user root -p 8080:8080 -v $(pwd):/var/model -v $(pwd)/static-assets:/static-assets ghcr.io/avisi-cloud/structurizr-site-generatr serve -w workspace.dsl -s /var/model/.preview -a /static-assets

Lessons learned

  • double volume mount from nested folder is causing an issue (and is not necessary)
  • -a parameter is not related for referencing !docs and !adrs (wasn't clear to me)

Case closed (as I don't expect investigating the double volume mount makes sense for you?)
Thank you for your help!

Thanks for reporting back, I'm glad to hear that you were able to solve this!