Skip to main content
Participating Frequently
March 10, 2022
Question

Per-application datasource not found after service restart.

  • March 10, 2022
  • 9 replies
  • 2978 views

I'm running into a rather strange issue and I don't know how to debug it. I'm using a per-application datasource feature in the `Application.cfc`:

 

this.datasources[ "bennadel" ] = { .... }

 

And, when I restart the ColdFusion service is sometimes says that the datasource cannot be found. This "state" seems to hold for the entire life of the application, and all requests coming into the application are breaking. But then, if I restart the ColdFusion service again, it works fine (probably). I'm kind of stumped here - not sure how to even go about debugging this.

    This topic has been closed for replies.

    9 replies

    Participating Frequently
    March 12, 2022

    Ok, I think I may have found a super hacky solution. Earier in this thread, I discovered that if I simply "touch" any value in the `this.datastructures`, some internal magical cache appears to get flushed and the application will bootstrap properly. This got me thinking about possibly doing this "touch" programmatically. What I've done now is include a timestamp when my config is cached in memory:

     

    private struct function getConfigSettings( boolean useCacheConfig = true ) {
    
    	var configName = "appConfig_#this.name#";
    
    	if ( useCacheConfig && server.keyExists( configName ) ) {
    
    		return( server[ configName ] );
    
    	}
    
    	var config = server[ configName ] = deserializeJson( PATH_TO_CONFIG_FILE );
    
    	// HACK: I'm having trouble with my "this.datasources" configuration bombing-out
    	// on server-start for reasons that I don't understand. Through trial-and-error,
    	// I've discovered that "touching" that structure fixes this issue. As such, I'm
    	// going to see if this date/time-stamp can act as a "touch" on that value.
    	config.loadedAt = getTickCount();
    
    	return( config );
    
    }

     

    As you can see, I'm injecting a `.loadedAt` property when this is cached in the `server` scope. Then, in my `this.datasources` struct, I now have:

     

    this.datasources = {
    	
    	"bennadel": {
    		username: this.config.dsn.username,
    		password: this.config.dsn.password,
    		driver: "MySQL",
    		class: "com.mysql.jdbc.Driver",
    		
    		// ...... truncated .......
    
    		// HACK: For reasons that I don't understand at all (and what is looking very
    		// much like a bug in ColdFusion), the datasources configuration occasionally
    		// bombs-out when the service-start up for the first time. But, I've
    		// discovered that simply "touching" this structure (ie, changing any property
    		// in it) appears to fix the problem (maybe by flushing some sort of cache).
    		// As such, I'm going to see if including a timestamp will act as a "touch".
    		// This timestamp is when the config object was cached. And, since it's cache
    		// whenever the onApplicationStart() method runs, if the application fails to
    		// bootstrap, the next request will get a newer timestamp.
    		_loaded_at_: this.config.loadedAt
    	}
    };
    this.datasource = "bennadel";

     

    Once I had this code in place, I started restarting the ColdFusion service. After about 7 restarts, I finally was able to reproduce the "datasource cannot be found error." However, unlike in previous tests, where this bad state _persisted_ indefinitely, I found that the next page request lead to a working application. I'm presuming this is befcause the next request triggered a new `onApplicationStart()` call, which in turn, reloaded the config, which in turn lead to a new `config.loadedAt` date/time stamp. It seems this new timestamp was enough to "touch" the structure, which cleared whatever crazy caching is going on.

     

    This is nuts!!! But, it seems to work 🤞

    Participating Frequently
    March 13, 2022

    This is _mostly_ working. The application bootstrapps now; however, I am sometimes seeing an issue in the bootstrapping process where ColdFusion complains that the connection pool isn't defined and I get a Null Pointer Exception during the SQL execution.

     

    Still working at it.

    BKBK
    Adobe Expert
    March 13, 2022

    I agree with you: this is nuts! Which could be an indication that we've been barking up the wrong tree. Your most recent findings - "_mostly_ working", then failing - imply that.

     

    What if all the caching behaviour is just the expected application-scoped caching on-application-start? Then any error or inconsistency that occurs prior to or in onApplicationStart() will persist till the application is restarted. 

     

    A review is in order. So, I am going back to the very beginning.

    The error message "Datasource bennadel could not be found" tells us that the application knows bennadel. This in turn implies that, if there was a problem it would probably be with the setting this.datasources.

     

    With that in mind, let's restart with no preconceptions. In other words, let us take for granted that ColdFusion will merrily accept the this.datasources/this.datasource combination:

     

    /* Application.cfc*/
    /* The datasource "bennadel" is only defined here. That is, 
    it is not defined in the ColdFusion Administrator. */
    
    this.datasources["bennadel"]={ ... };
    this.datasource="bennadel";

     

     

    Then this will mean that the cause of the problems is simple: wrong or incompatible datasource settings.

     

    To test this hypothesis, proceed as follows:

     

    1.  Stop ColdFusion.

    2. (If you haven't yet done so, import a recent MySQL Jar, as follows)
      Download the "Platform Independent" ZIP file from https://dev.mysql.com/downloads/connector/j/ . The latest version is the file mysql-connector-java-8.0.28.zip
      Unzip it. 
      Copy the file mysql-connector-java-8.0.28.jar to your ColdFusion lib directory. If there is any existing file in the lib directory whose name is of the form mysql-connector-java-x.x.x.jar  then delete it. 

    3.  Put the following settings in Application.cfc, replacing my settings with yours
      /* Note: MySQL5, not MySQL */
      this.datasources[ "bennadel" ] = {
              	 username: "root",
      		      password: "BkBk123",
      		       driver: "MySQL5",
      		       class: "com.mysql.jdbc.Driver",
      		       name:"bkbk_cf_mysql_db",
      		       url: "jdbc:mysql://127.0.0.1:3306/bkbk_cf_mysql_db?serverTimezone=Europe/London"
              };
              this.datasource="bennadel";​

       

    4.  Restart ColdFusion.

    5.  To test, run an arbitary CFM page.

      Any joy?

      

    Participating Frequently
    March 12, 2022

    Ok, I've spent the last hour-and-a-half restarting my live site and trying to add debugging. What a pain. It only actually breaks like 1 out of every 10 CF restarts. So, here's what I did:

     

    First, I wrapped my `this.datasources` definition in a try/catch and logged any error using `cflog()`. There were no errors to be found in this block of code, even when the application was having trouble bootstrapping.

     

    I added this to the top of my `onError()` handler:

     

    writeDump( getApplicationMetadata().datasource );
    writeDump( getApplicationMetadata().datasources.keyList() );
    writeDump( exception );
    abort;

     

    And, when the application got into a bad state, here's what it showed me:

     

     

    Note that both the `this.datasource` and `this.datasources` properties are correctly defined within `getApplicationMetadata()`

     

    Just bananas!!

    Participating Frequently
    March 11, 2022

    Ok, so I just tried one more thing. I restarted the ColdFusion service, and the datasource bombed-out. Then, all I did was update a value in the `this.datasources` - I changed `interval: 420` to `interval: 421`, re-uploaded my `Application.cfc` and the site immediately came online.

     

    To be clear, it has nothing to do with `interval`. I tried it a few more times, changing _different_ properties, and everytime I "touch" the `this.datasources` structure, the site immediately bootstraps and comes online. It's like an invalid version of the datasource is getting cached and then ColdFusion re-caches it if any of the keys change.

    Charlie Arehart
    Adobe Expert
    March 11, 2022

    This is all very interesting, and it raises some more questions that may help clarify things, and allow us to better understand whatever is going on:

    • You mentioned earlier that "once it gets in this state, every request is calling the `onApplicationStart()` method". Are you doing some logging or other debugging that shows that? 
    • Do you mean cf is calling it implicitly, or do you have code thaf calls it on some condition? 
    • About your last point here, is the change you make (to interval) being made to the one failing datasource, or perhaps any?
    • Are you inferring that Cf is automatically rerunning the onappstart, just because of that change? Or might you be calling it if some error handling code detects something not working? 
    • If you dump out the specific this.datasource array element that is "failing", do any of its values differ between when it IS failing and when it is NOT?

     

    In my experience with challenges like this, there will either be some head-slapping realization of something your code was causing, or some eyebrow-raising discovery of some cf behavior none of us is anticipating. 🙂 Looking forward to the "exciting conclusion" to the story. 

    /Charlie (troubleshooter, carehart. org)
    Participating Frequently
    March 11, 2022

    I had started to `dump` some data in the `onApplicationStart()`, and I noticed that all calls to the site were hitting this line of code, which is why I concluded that the app had not been bootstrapped and that ACF as implicitly calling this, attempting to bootstrap the app over and over (it never succesfully completes).

     

    I'll keep experimenting over the weekend. It's hard to test because the problem doesn't happen locally; and, it doesn't happen every time I spin-up the service 😄 Such a crazy problem!

    Participating Frequently
    March 11, 2022

    Ok, so I just restarted the server and the datasource bombed-out again. Here's what I discovered:

     

    • It is never making it past the `onApplicationStart()` method because I have some query-operations being triggered inside that function (preloading some in-memory structures from the DB). Meaning, once it gets in this state, every request is calling the `onApplicationStart()` method.
    • If I dumped-out the `getApplicationMetadata()` inside the `onApplicationStart()`, it shows _all the data_ that I expected, including the default `datasource` and the `datasources` configuration.
    • If I comment-out the data-pre-loading inside the `onApplicationStart()`, the application bootstraps. But then it errored due to missing pre-loaded data. BUT, if I then put this in the `onRequestStart()` code:

     

    ```

    applicationStop();

    location( url = cgi.script_name );

    ```

     

    ... in order to restart the application and refresh the page, then **everything starts up fine**.

     

    This is just so strange.

    Participating Frequently
    March 11, 2022

    Oh also, I tried copying the `this.datasources` and `this.datasource` configuration to inside the `onApplicationStart()` function - this made no difference. I'm pretty sure you _can't_ define that stuff there.

    Participating Frequently
    March 11, 2022

    Correct is:

    this.datasource = "bennadel"; // pre-defined in the Administrator
    this.datasources = { "bennadel1": { ... }, "bennadel2": { ... } }; // each distict from "bennadel"
    

     

    Alternatively,

    this.datasources = { "bennadel": { ... } }; 
    

    I thought the point of  `this.datasource` was to define which datasource should be used _by default_ in the queries. Meaning, my `<cfquery>` tags do **not** have a `datasource` attribute. They are like:

     

    <cfquery name="test">
        SELECT 1;
    </cfquery>

     

    I _believe_ it's the `this.datasource` that allows this to work. If I were to _just_ use the `this.datasources` **struct**, how would ColdFusion know which datasource to use in the `<cfquery>` tag?

    BKBK
    Adobe Expert
    March 11, 2022
     

    I'm running into a rather strange issue and I don't know how to debug it.


    By @bennadel22497347

    Debug suggestion:

    Run the following CFM page in the same directory as the Application.cfc:

    <cfscript>
    	try {
    		writedump(new Application());
    	} 
    	catch (any e) {
    		writedump(var=e, label="Oops!");
    	}
    </cfscript>

     

    BKBK
    Adobe Expert
    March 11, 2022

    Hi @bennadel22497347 , I only have questions. But I hope they help.

    1.  Is the datasource "bennadel" already configured in the ColdFusion Administrator?
           If so, then the code you've shown will be a repetition. The correct initialization code will probably be
           
           this.datasource="bennadel";

    2.   Have you ensured that all the necessary datasource attributes - and appropriate values - are included in { ... }?
            For example, might the attributes you currently use make ColdFusion to create a connection each time?
            I would provide in { ... } , as a minimum, the attributes required to create a datasource in the ColdFusion Administrator. (Mind the default values)
    Adobe Expert
    March 10, 2022

    I don't have a good debugging suggestion either. When I run into a problem like this, I generally just go in and yank on things until they work or break in a different way.

     

    I've never heard of setting those "this." variables in onApplicationStart, onServerStart or onSessionStart. But it seems to work for Mark when he uses onApplicationStart, so try that! In the worst case, it still won't work intermittently and you're back where you started. You might also just see if there's a minor point release to the JVM beyond what you're using. Will upgrading to that work? Who knows? But this kind of random "pushing on buttons" might solve your problem even if you never find out why. Or, you might try using CFTRY/CFCATCH or its CFSCRIPT equivalent around the code you're using here. You shouldn't need it, but again, who knows?

     

    Dave Watts, Eidolon LLC

    Dave Watts, Eidolon LLC
    New Participant
    March 10, 2022

    To add to Charlie's answer, I would also ask where are you setting this? Are you setting in onApplicationStart() (this is where I would set it). I'm convinced there's a race condition of some sort that seems to happen sometimes. I also include a function inside of onRequestStart that lets me restart the application with a long URL variable. Just in case there's some kind of weird issue that happens. But like Charlie said, in this kind of thing I go back to the basics and just start dumping out the app scope and meta data and see what CF thinks it is doing. Is it ALL the app variables not setting, just some? Ping me if you run into more issues!

    Participating Frequently
    March 10, 2022

    Hey all! 👋 so, the datasource that I'm defining is in the `Application.cfc` pseudo-constructor - basically right after I setup the name, mappings, serialization key-casing, etc. It was my understanding that this kind of stuff _had_ to be done in the pseudo-constructor; but, maybe that understanding it outdated? It sounds like @Mark Takata is saying that I can do it inside of `onApplicationStart()`. If that's true, this is news to me.

     

    @Charlie Arehart good idea with the `getApplicationMetadata()` test. It's a bit tricky, this since this _only_ happens in production and I don't want everyone to suddenly get a dump of my app configuration values 🤣 but, I can probalby put it in some separate template and maybe even sanitize the password just in case.

     

    I'll do that stuff and report back. Also, I'll try to hang-out in the forum more. 

    Charlie Arehart
    Adobe Expert
    March 10, 2022

    Great to see the replies from you both. First, yep, no need for others to see the dump, Ben. I'd said, "I'd recommend doing it in a separate template rather than the Application.cfc itself.

     

    And as for whether to do the set in onappstart or not, I'm ambivalent. I'd just asked whether the set was in a method or not. As for Mark's observation, I think he's saying the race condition was when it WAS in onappstart--though it could definitely happen outside of it. 

     

    But I will press again my question about whether the set is inside anything that can affect its execution...not just an if test but perhaps something less obvious like a try/catch or cflock. 

     

    And Mark, it would be awesome if you'll be in here often going forward. It's been mostly BKBK and myself holding down the fort, with also Dave Watts and Priyank less often (but greatly appreciated), then some others still less often. No slight intended to anyone who does help. 

     

    It would just be great to see if more "reinforcements" might be arriving. It does take effort, but "many hands make light work". 🙂

     

    As you'll see here, not EVERYONE has moved to slack or twitter for help. 🙂  And the knowledge shared here is far more easily found in web searching. 

    /Charlie (troubleshooter, carehart. org)
    Charlie Arehart
    Adobe Expert
    March 10, 2022

    Hey, Ben, and a hearty welcome to the forums. We've missed you. 🙂

     

    First, can you do a dump of getapplicationmetadata()? I'd recommend doing it in a separate template rather than the Application.cfc itself. Do you see the datasource and ALL other this scope things you set?

     

    If you do not, assess whether you may have any code that could affect that surrounding the setting of those vars, like a try/catch or even a cflock with perhaps throwontimeout="no".

     

    Also, are those settings created in a method in the cfc or outside of any (what is termed the "pseudo-constructor", for the sake of other readers)?

     

    It would be awesome if you may stick around and share your wealth of knowledge with folks here, but I realize you've got more irons in the fire than a blacksmith at a rodeo. 🙂 

    /Charlie (troubleshooter, carehart. org)