Global InspectTemplates()

Hi,

We’re trying to make use of the “Inspect Templates: Never” setting (running Lucee 5.4 and Lucee 6.2) to make deployments less fragile and gain a little performance. We have a couple of Lucee servers with identical Apache/Tomcat and Lucee configs running behind a load balancer, files are on a common NFS share. The servers are each running one single context, in the case of 6.2 we’re running in single mode.

Now I understand that we’d need to call InspectTemplates() for each Application context on each server in order to re-compile changed templates. This complicates things for our use case unnecessarily, as we’re running quite a number of Applications, a lot of them sharing code, but not all of them. It would be really nice to not have to issue InspectTemplates() for each single Application, but just once per server.

I tried using SystemCacheClear() for template, component and customtag to that effect, I tried combining this with a PagePoolClear(), but changes in an include file would still not be picked up - we found that the only way for Lucee to pick up changes done to included templates (i.e. include files) was to run InspectTemplates() on each affected Application. Or restart the Lucee instance.

I guess I must be missing something. Surely there has to be a way to force a global InspectTemplates() on the full server context and any kind of user code, i.e. CFML, CFCs, server side configured customTags and components as well as Application level mapped code?

I know that it would cause a short performance impact when the server would need to recompile the codebase, but I am fairly sure that we could live with that. The alternative would be to register a separate inspectTemplates()-endpoint for each Application and register this in a refresh script, which feels overly complex.

What am I missing here?

Kind regards

Markus

Agreed, we have an open ticket about this

https://luceeserver.atlassian.net/browse/LDEV-3388

In the meantime, the following snippet loops over all the active application scopes and calls inspectTemplate(), which won’t update any applications which aren’t active

<cfscript>
	stashApplicationName = getApplicationSettings().name;
	applications = getPageContext()
		.getCFMLFactory()
		.getScopeContext()
		.getAllApplicationScopes();
	structEach(applications, function(k, v){
		cfapplication(action="update", name=k);
		dump(getApplicationSettings().name);
		inspectTemplates();
	});
	cfapplication(action="update", name=stashApplicationName);
</cfscript>

Actually I don’t think that will work as the mappings in the applicationContext are only loaded per request, for me dump(getApplicationSettings().mappings); is coming back empty, YMMV

You could also call applicationStop() in the above code to force all applications to restart, combined with calling inspectTemplates() in onApplicationStart() is a good approach.

1 Like

Thank you for clearing this up. Our code is not in a monorepo and there are a fair number of shared repos between our web apps. Our developers love the idea that inspectTemplate=“never” allows them to copy code into production in any order without worrying about order of dependencies and only when they are done with deployment telling Lucee to check for changes. applicationStop() is too harsh a measure to do what we want and I can confirm that just calling inspectTemplates() while the application name is being set programmatically does not deal with the code that is in application specific mappings.

I have therefore extended our deploy tool so devs can change inspectTemplates to “once” after they have pulled all their code; then they can run their test(s) on all servers and switch back to inspectTemplates=“never” when they’re done. That seems to do exactly what we need for now.

component{

	/**
	 * gets the current value of the inspectTemplate setting
	 * 
	 * returns a string, should be either once or never
	 */
	remote string function getSetting() returnFormat="JSON" {
		var adminPassword = getAdminPassword();
		var performanceSettings = getSettings();
		return performanceSettings.inspectTemplate?:"unknown";
	}

	/**
	 * sets the current value of the inspectTemplate setting
	 *
	 * @value allowed values: once, never
	 */
	remote boolean function setSetting(required string value) returnFormat="JSON" {
		var success = false;
		var adminPassword = getAdminPassword();
		switch(value){
			case "once":
			case "never":
				var performanceSettings = getSettings();
				cfadmin(
					type="server"
					password=adminPassword
					action="updatePerformanceSettings"
					inspectTemplate=lCase(value)
					typeChecking="#!isNull(performanceSettings.typeChecking) && performanceSettings.typeChecking EQ true#"
				);
				success = true;
			break;
		}
		return success;
	}

	private struct function getSettings(){
		var adminPassword = getAdminPassword();
		var performanceSettings;
		cfadmin(
			type="server"
			password=adminPassword
			action="getPerformanceSettings"
			returnVariable="performanceSettings"
		);
		return performanceSettings;
	}

	private string function getAdminPassword(){
		return new credentials().getPassword();
	}
	
}