jamesfredley commented on issue #15330:
URL: https://github.com/apache/grails-core/issues/15330#issuecomment-3885671270

   The Problem
   
   In application.yml (line 35), the configuration is:
   ```
   environments:
       development:
           serverURL: https://grails7-absolute-link-issue.domain.com
   ```
   
   The Fix
   Change the configuration to one of these patterns:
   Option 1: Environment-specific (recommended)
   ```
   environments:
       development:
           grails:
               serverURL: https://grails7-absolute-link-issue.domain.com
   ```
   Option 2: Global setting
   ```
   grails:
       serverURL: https://grails7-absolute-link-issue.domain.com
   ```
   
   The configuration needs to be nested under the `grails:` key, not directly 
under `environments.development:`.
   
   
   The null you're seeing is a race condition in the controller code, not a 
configuration problem.
   Look at the controller logic:
   ```
   def index() {
       String link
       Thread.start {              // Starts a NEW thread asynchronously
           try {
               link = grailsLinkGenerator.link(...)  // Runs in background
           } catch (Exception e) {
               e.printStackTrace()
           }
       }
       
       // Main thread continues immediately without waiting!
       
       String link2 = grailsLinkGenerator.link(...)  // Executes in main thread
       
       render link + link2  // Renders BEFORE background thread completes
   }
   ```
   What happens:
   1. Line 12: Thread starts in background
   2. Line 26-31: Main thread immediately generates link2 
   3. Line 33: render link + link2 executes before the background thread 
finishes
   4. At this point, link is still null because the thread hasn't completed yet
   
   Updated controller that does not have this issue:
   
   ```
   package grails7.absolute.link.issue
   
   import grails.web.mapping.LinkGenerator
   import java.util.concurrent.Callable
   import java.util.concurrent.Executors
   import java.util.concurrent.Future
   
   class MakeLinkController {
   
       LinkGenerator grailsLinkGenerator
   
       def index() {
           // Use ExecutorService to properly wait for thread completion
           def executor = Executors.newSingleThreadExecutor()
           
           try {
               // Submit task and get Future
               Future<String> future = executor.submit(new Callable<String>() {
                   @Override
                   String call() throws Exception {
                       return grailsLinkGenerator.link(
                               absolute: true,
                               controller: 'MakeLink',
                               action: 'index',
                               id: 1
                       )
                   }
               })
   
               // Get result from background thread (waits for completion)
               String link = future.get()
   
               // Generate link in web context
               String link2 = grailsLinkGenerator.link(
                       absolute: true,
                       controller: 'MakeLink',
                       action: 'index',
                       id: 1
               )
   
               render """
   Link from background thread: ${link}
   Link from web context: ${link2}
   """
           } finally {
               executor.shutdown()
           }
       }
   }
   ```
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to