Hi, we're currently trying to migrate our Grails 2...
# questions
i
Hi, we're currently trying to migrate our Grails 2 application to Grails 5. Thanks to this channel, we've made progress to the point where we can start the application, and most things are running smoothly. However, we're facing a fundamental issue: the compilation process is taking a very long time, and even the smallest change triggers a complete recompilation. For instance, modifying just one line of code necessitates 5-6 minutes of compilation. We're using Java 17 and Grails 5.3.3. The number of Groovy and Java files is around 1000, totaling approximately 30k lines of code. We've already tried all the standard solutions. Here's our compile directive:
Copy code
tasks.withType(GroovyCompile) {
    options.fork = true
    options.forkOptions.memoryMaximumSize = '4096m'
    options.incremental = true
}
This are our dependencies from Grails (Application specific libraries excluded)
Copy code
developmentOnly("org.springframework.boot:spring-boot-devtools")
compileOnly "io.micronaut:micronaut-inject-groovy"
console "org.grails:grails-console"
implementation "org.springframework.boot:spring-boot-starter-logging"
implementation "org.springframework.boot:spring-boot-starter-validation"
implementation "org.springframework.boot:spring-boot-autoconfigure"
implementation "org.grails:grails-core"
implementation "org.springframework.boot:spring-boot-starter-actuator"
implementation "org.springframework.boot:spring-boot-starter-tomcat"
implementation "org.grails:grails-web-boot"
implementation "org.grails:grails-logging"
implementation "org.grails:grails-plugin-rest"
implementation "org.grails:grails-plugin-databinding"
implementation "org.grails:grails-plugin-i18n"
implementation "org.grails:grails-plugin-services"
implementation "org.grails:grails-plugin-url-mappings"
implementation "org.grails:grails-plugin-interceptors"
implementation "org.grails.plugins:cache"
implementation "org.grails.plugins:async"
implementation "org.grails.plugins:scaffolding"
implementation "org.grails.plugins:hibernate5"
implementation "org.hibernate:hibernate-core:5.6.11.Final"
implementation "org.grails.plugins:events"
implementation "org.grails.plugins:gsp"
profile "org.grails.profiles:web"
Maybe we are just missing something? After reading about issues with compiling Groovy files here, I'm considering transferring everything to Java or Kotlin. However, this effort wouldn't be worthwhile if it's not related to the problem at hand.
g
I am using Java 8 with the old Spring Loaded which works for most of the changes done to the code and requires a lot less restarts. In my
build.gradle
file I have this:
Copy code
def frameworkVersion
    def javaVersion = JavaVersion.current()
    if (javaVersion == JavaVersion.VERSION_1_8) {
        frameworkVersion = '23.8-SNAPSHOT'
        println "*** JAVA ${javaVersion} - SPRING LOADED" // WORKS ONLY WITH JAVA 8
        println "*** Reloads modified classes without restarting the application"
        agent "org.springframework:springloaded:1.2.8.RELEASE"
        runtimeOnly "com.bertramlabs.plugins:asset-pipeline-grails:3.4.7"
        runtimeOnly "io.methvin:directory-watcher:0.9.6" // Native OSX file watcher

    } else {
        frameworkVersion = '23-SNAPSHOT'
        println "*** JAVA ${javaVersion} - SPRING DEV TOOLS"
        println "*** Restarts the whole application when BootStrap.groovy is modified"
        println "*** NOTE: switch to JAVA 8 to enable hot reloading of modified classes"
        developmentOnly "org.springframework.boot:spring-boot-devtools"
        runtimeOnly "com.bertramlabs.plugins:asset-pipeline-grails:4.3.0"
    }
This way we develop with Java 8 and deploy with Java 17
NOTE: asset-pipeline has different versions since they have departerd from Java 8 so we are using the latest Java 8 compatible one when developing
i
Thank you giagio, that sound like a good workaround, I will try it. However that's not what I would expect when I do a migration to be more up to date and use new technologies. So it is related to the java version and in grails catching up with this changes was too time consuming or even just not possible? Because in Grails 2.5.6 even a full compile took less than 2 minutes.
p
I personally wouldn't recommend using Spring loaded as it is not maintained any longer. The default option with Grails 5 is using Spring Boot Devtools which is slower comparatively to Spring Loaded or you could JRebel (a paid solution). Please note are baselining to Java 17 as minimum required for Grails 7. So at some point you will be forced to move away from Spring Loaded.
g
@IndianerJones the "groove" these days is to decouple applications in small chunks that can be restarted quickly, so everybody is running there and less people is interested in developing a tool to NOT restart the JVM. So the real issue is that nobody has interest in porting SpringLoaded to JVM > 8. Even if many competitor languages has the "hot-reload" feature embedded in their VM cause they are interpreted languages. Java is mostly used in big companies that have no problems paying people to work on microservices architectures even if they are more expensive to maintain (yes, they are at the moment). The thing is that the use cases for such architectures like having 1000000000 users (Eg. NETFLIX) is not the use case for many other businesses (Eg. I.ve built a web interface as a primary touch interface for an insutrial machine using Grails, websockets, sockets and serial port communications to update the GUI)
@puneetbehl It's nice to hear from you, I hope everything is good and proceeding well with the next release of Grails, I am a big fan of you 🙂 I know we will have to move on, but at the moment it's too convenient
i
Actually we cannot stay on Java 8 for development, we have libraries that require at least java 11. Maybe I didn't explain it correctly, my issue is that the compile process is now slower than before and everytime the whole project is compiled. My experience on Grails 2 and less is that only changed classes will be compiled an than you can start again. The starting takes some time, but way less than we have now. So I would be really happy if only changed classes would be compiled. Is the recompile of the whole project an expected behavior?
g
Yes it is. The projects gets recompiled each time you save a file. Technically only the changed files get recompiled but the whole application is restarted. You can change the behaviour for example we have configured it to restart ONLY when BootStrap.groovy gets modified (I usually issue a 'touch BootStrap.groovy' and it works). This is my setup:
Copy code
spring:
  devtools:
    restart:
      trigger-file: BootStrap.groovy
      quiet-period: 2000
      poll-interval: 3000
      additional-paths: .
      additional-exclude:
        - '*.gsp'
        - '**/*.gsp'
        - '*.gson'
        - '**/*.gson'
        - 'logback.groovy'
        - '*.properties'
        - '**/*BootStrap.groovy'
i
@giangio That "Technically only the changed files get recompiled but the whole application is restarted." was the thing I was looking for, you brought me on the right track! When doing a gradle compileGroovy -i I saw that my jaxb dependencies always triggered a full compile. I wasn't able to fix it yet, bu hope to find a solution by checking the dependencies for version conflicts. Thank you for your support. The suggestions you propose for reducing compilations are (at least yet) not what I want to do. We try to keep things as simple as possible and adding custom steps to compilation will make it harder for others to join the team or support.
👍 1
p
Apologies for any oversight. In versions of Grails prior to Grails 5, the Grails reloading agent was the primary mechanism for hot-reloading. The Grails reloading agent was a dedicated tool integrated into the Grails framework, designed to dynamically reload changes made to the codebase during the development phase. This functionality allowed developers to experience immediate updates without the need for a complete application restart. The Grails reloading agent worked by monitoring changes in the application's source code and automatically reloading modified classes, thereby facilitating a smoother and more efficient development workflow. This real-time feedback mechanism significantly reduced the turnaround time for testing and iterating on code changes, enhancing the overall developer experience. Additionally, another option available in earlier Grails versions was Spring Loaded, specifically designed to work with Java 8. However, it's important to note that Spring Loaded is no longer actively maintained. While it provided an alternative for hot-reloading, its use is generally discouraged in favor of more modern and supported options. As technology evolves, Grails 5 and later versions have transitioned to using Spring Boot devtools as the default hot-reloading mechanism. However, for users working with Grails versions predating Grails 5, the Grails reloading agent remains the established tool for managing dynamic code changes during development. Developers are encouraged to be aware of the maintenance status when considering hot-reloading options for their projects. It's important to note that in Grails 5 and later, the Spring Boot devtools provide enhanced capabilities and compatibility with newer Java versions. To enhance the performance of Spring Boot DevTools, consider disabling automatic restart in your application properties, excluding unnecessary resources from triggering restarts, and fine-tuning classloaders and resource monitoring timing. Additionally, adjust filesystem watch limits to optimize performance, and if needed, allocate more memory by increasing the heap size in your configuration. Experiment with these settings to find the optimal configuration for your development environment, striking a balance between convenience and performance. For further details and customization options, please refer to the documentation at https://docs.spring.io/spring-boot/docs/2.7.18/reference/html/using.html#using.devtools.
i
Thank you, when we have finished the migration we will fine tune our configuration, it sounds like we could reduce our waiting for compilation time a lot 👍. Just for completion, we actually hat no issue with Grails, it was related to Gradle: https://github.com/gradle/gradle/issues/27856 If you are using multirelease dependencies you should update your gradle to at least 7.6.4.