Why does cacheTimeout setting of renderView() in ColdBox application have no effect? - cfml

I'm developing a ColdBox application with modules and wanted to use it's caching functionality to cache a view for some time.
component{
property name="moduleConfig" inject="coldbox:moduleConfig:mymodule";
...
function widget(event, rc, prc){
var viewData = this.getData();
return renderView(
view = "main/widget",
args = viewData,
cache = true,
cacheSuffix = ":" & moduleConfig.entryPoint,
cacheTimeout = 2
);
}
}
I tried to set the default caching config by adding the following info to my Cachebox.cfc and removed the cacheTimeout from the code above:
cacheBox = {
defaultCache = {
objectDefaultTimeout = 1, //two hours default
objectDefaultLastAccessTimeout = 1, //30 minutes idle time
useLastAccessTimeouts = false,
reapFrequency = 5,
freeMemoryPercentageThreshold = 0,
evictionPolicy = "LRU",
evictCount = 1,
maxObjects = 300,
objectStore = "ConcurrentStore", //guaranteed objects
coldboxEnabled = false
},
caches = {
// Named cache for all coldbox event and view template caching
template = {
provider = "coldbox.system.cache.providers.CacheBoxColdBoxProvider",
properties = {
objectDefaultTimeout = 1,
objectDefaultLastAccessTimeout = 1,
useLastAccessTimeouts = false,
reapFrequency = 5,
freeMemoryPercentageThreshold = 0,
evictionPolicy = "LRU",
evictCount = 2,
maxObjects = 300,
objectStore = "ConcurrentSoftReferenceStore" //memory sensitive
}
}
}
};
Though that didn't have any influence on the caching. I've also tried to add the config above to my Coldbox.cfc.
Even if I create a completely new test app via CommandBox via coldbox create app MyApp, then only set the the caching in Cachebox.cfc to one minute, set viewCaching = true in Coldbox.cfc, and set event.setView( view="main/index", cache=true ) in the Main.cfc, it doesn't work as expected.
No matter what I do, the view is always cached for at least 5 minutes.
Is there something I am missing?

Make sure you have enabled view caching in your ColdBox configuration. Go to the /config/ColdBox.cfc file and add this key:
coldbox = {
// Activate view caching
viewCaching = true
}
Also, did you mistype the name of the CFC you changed for the caching above? Those changes should be in the /config/CacheBox.cfc file, not in /config/ColdBox.cfc.

Obviously, also the the reapFrequency in the /config/ColdBox.cfc needs to be set to a smaller value in order to let the cache entry be removed earlier.
Though, as the documentation states:
The delay in minutes to produce a cache reap (Not guaranteed)
It is not guaranteed that the cached item it really removed after that time, so it can be that the cache is empty after 3 minutes even when reapFrequency is set to 1.

Related

How do I force rebuild of all snapshot dependencies in my teamcity build trigger?

I have a list of build types in my settings.kts:
val buildChain = listOf(build1, build2, build3, ...)
I define the following chain of snapshot dependencies:
for ((previous, current) in buildChain.zip(buildChain.drop(1))) {
current.dependencies {
snapshot(previous) {
reuseBuilds = ReuseBuilds.NO
onDependencyFailure = FailureAction.FAIL_TO_START
onDependencyCancel = FailureAction.FAIL_TO_START
}
}
}
With that, build<N> depends on build<N-1>. Then I define the following build type that runs the whole build chain:
val buildChainRunner = BuildChainRunner(headOfBuildChain = buildChain.last())
where
class BuildChainRunner(
headOfBuildChain: BuildType,
) : BuildType({
name = "Build Chain Runner"
dependencies {
snapshot(headOfBuildChain) {
reuseBuilds = ReuseBuilds.NO
onDependencyFailure = FailureAction.ADD_PROBLEM
onDependencyCancel = FailureAction.ADD_PROBLEM
}
}
triggers {
schedule {
schedulingPolicy = daily {
hour = 2
minute = 0
timezone = "Europe/Amsterdam"
}
branchFilter = "+:<default>"
triggerBuild = always()
withPendingChangesOnly = false
}
}
[...]
}
Now, when the build gets triggered by the schedule trigger, it doesn't necessarily rebuilds all builds from the chain. What I would like to do is the very same as this:
I thought that would be automatically the case because of
reuseBuilds = ReuseBuilds.NO
but unfortunately, it doesn't work. When I trigger the build manually and set "rebuild snapshot dependencies" to "all", then it works as I expect. What am I doing wrong in my kotlin DSL configuration?

LrDialogs.runOpenDialog not working inside LrExportServiceProvider

I am trying to create a Lightroom Classic Export Service Provider plugin that has a Browse... button in the sectionsForTopOfDialog to allow the user to choose a Folder related to the plugin. The open dialog is attached to the action of the viewFactory:push_button, and the dialog opens successfully, but it seems like the rest of the push button's action is never executed, as if the runOpenPanel function never returned.
How can I create a Browse button to allow the user to select a folder and get the result? (I want to store the result in the propertyTable, this part is omitted from the code.)
Complete plugin code to reproduce the issue below. (Create a folder named runOpenDialogMCVE.lrdevplugin folder, add these files, load it as a Lightroom plugin.)
-- Info.lua
return {
LrSdkVersion = 3.0,
LrSdkMinimumVersion = 1.3, -- minimum SDK version required by this plugin
LrPluginName = "RunOpenPanel MCVE",
LrToolkitIdentifier = 'com.example.lightroom.runopenpanelmcve',
LrExportServiceProvider = {
title = "LrDialogs.runOpenPanel MCVE",
file = 'ExportServiceProvider.lua',
},
VERSION = { major=0, minor=1, revision=0 },
}
-- ExportServiceProvider.lua
local LrDialogs = import 'LrDialogs'
local LrLogger = import 'LrLogger'
local LrView = import 'LrView'
local logger = LrLogger("LrDialogs.runOpenDialogMCVE")
local viewFactory = LrView.osFactory()
logger:enable("print")
local ExportServiceProvider = {}
function ExportServiceProvider.sectionsForTopOfDialog( propertyTable )
return {
{
title = "LrDialogs.runOpenDialog MCVE",
viewFactory:row {
viewFactory:push_button {
title = "Browse...",
action = function ()
logger:trace("Opening dialog...")
LrDialogs.message("Will open dialog after this.")
local result = LrDialogs.runOpenPanel( {
title = "Location",
prompt = "Choose",
canChooseDirectories = true,
canChooseFiles = false,
allowsMultipleSelection = false,
} )
-- I would expect the code below to execute, but it never does.
-- No trace is printed and none of the dialogs below are shown.
logger.trace("Closing dialog. "..tostring(result))
if result ~= nil then
logger:trace("Chosen folder: "..result[1])
LrDialogs.message("Choseen folder: "..result[1])
else
logger:trace("Cancelled")
LrDialogs.message("Cancelled")
end
end,
},
},
},
}
end
return ExportServiceProvider
I'm using Lightroom version 12.0 on MacOS.

How to keep HTTP/2 connection alive till the request / response session is complete?

I am currently using HttpDeclarePushto exploit the Server Push feature in HTTP/2.
I am able to successfully create all the parameters that this function accepts. But the issue is when HttpDeclarePushexecutes it returns a value of 1229 (ERROR_CONNECTION_INVALID) - https://learn.microsoft.com/en-us/windows/desktop/debug/system-error-codes--1000-1299-.
On further investigation I found that the HttpHeaderConnection in _HTTP_HEADER_ID (https://learn.microsoft.com/en-us/windows/desktop/api/http/ne-http-_http_header_id) is actually passed in the function as 'close'. That implies that on every request response the server closes the connection and that is also happening in my case, I checked it in the log.
Here is the code.
class http2_native_module : public CHttpModule
{
public:
REQUEST_NOTIFICATION_STATUS OnBeginRequest(IN IHttpContext * p_http_context, IN IHttpEventProvider * p_provider)
{
HTTP_REQUEST_ID request_id;
const HTTPAPI_VERSION version = HTTPAPI_VERSION_2;
auto pHttpRequest = p_http_context->GetRequest();
auto phttpRequestRaw = pHttpRequest->GetRawHttpRequest();
HANDLE p_req_queue_handle = nullptr;
auto isHttp2 = phttpRequestRaw->Flags;
try {
const auto request_queue_handle = HttpCreateRequestQueue(version, nullptr, nullptr, NULL, &p_req_queue_handle);
const auto verb = phttpRequestRaw->Verb;
const auto http_path = L"/polyfills.0d74a55d0dbab6b8c32c.js"; //ITEM that I want to PUSH to client
const auto query = nullptr;
request_id = phttpRequestRaw->RequestId;
auto headers = phttpRequestRaw->Headers;
auto connId = phttpRequestRaw->ConnectionId;
WriteEventViewerLog(L"OnBeginRequest - Entering HTTPDECLAREPUSH");
headers.KnownHeaders[1].pRawValue = NULL;
headers.KnownHeaders[1].RawValueLength = 0;
const auto is_success = HttpDeclarePush(p_req_queue_handle, request_id, verb, http_path, query, &headers);
sprintf_s(szBuffer, "%lu", is_success);
Log("is_success value", szBuffer); //ERROR CODE 1229 here
HttpCloseRequestQueue(p_req_queue_handle);
}
catch (std::bad_alloc & e)
{
auto something = e;
}
return RQ_NOTIFICATION_CONTINUE;
}
I even tried to update the header connection value as below but it still gives me 1229.
headers.KnownHeaders[1].pRawValue = NULL;
headers.KnownHeaders[1].RawValueLength = 0;
I understand from https://http2.github.io/http2-spec/ that HTTP/2 actually ignores the content in HTTP HEADERs and uses some other mechanism as part of its FRAME.
This brings us to the next question on how we can keep the connection OPEN and is it something related to the FRAME (similar to HEADER) that HTTP2 uses, if so, how C++ or rather Microsoft helps us to play and exploit with the FRAME in HTTP2?

Grid Events and oldValue versus newValue

When updating entities in my cache, the oldValue=newValue in the event, unless I do a put with the original object instance. This is of course not always possible.
Here is a simplified example.
IgnitePredicate<CacheEvent> locLsnr = evt -> {
// do something
};
ignite.events().localListen(locLsnr,EventType.EVT_CACHE_OBJECT_PUT);
IgniteCache<TradeKey, Trade> cache = ignite.getOrCreateCache("MyCache");
Trade trade1 = new Trade();
trade1.setId(1);
trade1.setSize(10);
cache.put(new TradeKey(trade.getId()), trade1);
// event is generated
//evt.oldValue is null, no problem
trade1.setSize(20);
cache.put(new TradeKey(trade.getId()), trade1);
// event is generated
// evt.oldValue().getSize() is 10, evt.newValue().getSize() is 20, this is GOOD
But, if I retrieve the trade from the cache again before updating (from another part of the application for example), I am not able to see what the old value was in the event. Old value will just show the new value.
IgnitePredicate<CacheEvent> locLsnr = evt -> {
// do something
};
ignite.events().localListen(locLsnr,EventType.EVT_CACHE_OBJECT_PUT);
IgniteCache<TradeKey, Trade> cache = ignite.getOrCreateCache("MyCache");
Trade trade1 = new Trade();
trade1.setId(1);
trade1.setSize(10);
cache.put(new TradeKey(trade.getId()), trade1);
// event is generated
//evt.oldValue is null, no problem
trade1 = cache.get(new TradeKey(1)); // or could be a query or any search on the cache
trade1.setSize(20);
cache.put(new TradeKey(trade.getId()),trade1);
// event is generated
// evt.oldValue().getSize() is 20, evt.newValue().getSize() is 20, this is BAD
Any advice?
Thanks.
This is also discussed on Apache Ignite user forum: http://apache-ignite-users.70518.x6.nabble.com/Grid-Events-and-oldValue-versus-newValue-td10577.html

EPiServer 9 - Add block to new page programmatically

I have found some suggestions on how to add a block to a page, but can't get it to work the way I want, so perhaps someone can help out.
What I want to do is to have a scheduled job that reads through a file, creating new pages with a certain pagetype and in the new page adding some blocks to a content property. The blocks fields will be updated with data from the file that is read.
I have the following code in the scheduled job, but it fails at
repo.Save((IContent) newBlock, SaveAction.Publish);
giving the error
The page name must contain at least one visible character.
This is my code:
public override string Execute()
{
//Call OnStatusChanged to periodically notify progress of job for manually started jobs
OnStatusChanged(String.Format("Starting execution of {0}", this.GetType()));
//Create Person page
PageReference parent = PageReference.StartPage;
//IContentRepository contentRepository = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<IContentRepository>();
//IContentTypeRepository contentTypeRepository = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<IContentTypeRepository>();
//var repository = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<IContentRepository>();
//var slaegtPage = repository.GetDefault<SlaegtPage>(ContentReference.StartPage);
IContentRepository contentRepository = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<IContentRepository>();
IContentTypeRepository contentTypeRepository = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<IContentTypeRepository>();
SlaegtPage slaegtPage = contentRepository.GetDefault<SlaegtPage>(parent, contentTypeRepository.Load("SlaegtPage").ID);
if (slaegtPage.MainContentArea == null) {
slaegtPage.MainContentArea = new ContentArea();
}
slaegtPage.PageName = "001 Kim";
//Create block
var repo = ServiceLocator.Current.GetInstance<IContentRepository>();
var newBlock = repo.GetDefault<SlaegtPersonBlock1>(ContentReference.GlobalBlockFolder);
newBlock.PersonId = "001";
newBlock.PersonName = "Kim";
newBlock.PersonBirthdate = "01 jan 1901";
repo.Save((IContent) newBlock, SaveAction.Publish);
//Add block
slaegtPage.MainContentArea.Items.Add(new ContentAreaItem
{
ContentLink = ((IContent) newBlock).ContentLink
});
slaegtPage.URLSegment = UrlSegment.CreateUrlSegment(slaegtPage);
contentRepository.Save(slaegtPage, EPiServer.DataAccess.SaveAction.Publish);
_stopSignaled = true;
//For long running jobs periodically check if stop is signaled and if so stop execution
if (_stopSignaled) {
return "Stop of job was called";
}
return "Change to message that describes outcome of execution";
}
You can set the Name by
((IContent) newBlock).Name = "MyName";