From 167a315b3d70521a8ba530aa26e0b04b63fb6a56 Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Sat, 1 Feb 2025 15:06:45 +0100 Subject: [PATCH] LDEV-4818 add sessionCommit() function https://luceeserver.atlassian.net/browse/LDEV-4818 --- .../functions/system/SessionCommit.java | 15 ++++++++++++++ .../type/scope/storage/IKHandlerCache.java | 7 ++++--- core/src/main/java/resource/fld/core-base.fld | 11 +++++++++- test/tickets/LDEV2135.cfc | 20 ++++++++++++++++--- .../LDEV2135/cfml-session/secondRequest.cfm | 6 +++++- .../cfml-session/testThreadSession.cfm | 9 ++++++--- 6 files changed, 57 insertions(+), 11 deletions(-) create mode 100644 core/src/main/java/lucee/runtime/functions/system/SessionCommit.java diff --git a/core/src/main/java/lucee/runtime/functions/system/SessionCommit.java b/core/src/main/java/lucee/runtime/functions/system/SessionCommit.java new file mode 100644 index 0000000000..13750b0f9c --- /dev/null +++ b/core/src/main/java/lucee/runtime/functions/system/SessionCommit.java @@ -0,0 +1,15 @@ +package lucee.runtime.functions.system; + +import lucee.runtime.PageContext; +import lucee.runtime.PageContextImpl; +import lucee.runtime.exp.PageException; +import lucee.runtime.ext.function.Function; + +public class SessionCommit implements Function { + private static final long serialVersionUID = -2243745577257724777L; + + public static String call(PageContext pc) throws PageException { + ((PageContextImpl) pc).sessionScope().touchAfterRequest(pc); + return null; + } +} \ No newline at end of file diff --git a/core/src/main/java/lucee/runtime/type/scope/storage/IKHandlerCache.java b/core/src/main/java/lucee/runtime/type/scope/storage/IKHandlerCache.java index 34c48dd278..78e9b59c5c 100644 --- a/core/src/main/java/lucee/runtime/type/scope/storage/IKHandlerCache.java +++ b/core/src/main/java/lucee/runtime/type/scope/storage/IKHandlerCache.java @@ -36,16 +36,16 @@ public IKStorageValue loadData(PageContext pc, String appName, String name, Stri Object val = cache.getValue(key, null); if (val instanceof byte[][]) { ScopeContext.info(log, - "load existing data from cache [" + name + "] to create " + strType + " scope for " + pc.getApplicationContext().getName() + "/" + pc.getCFID()); + "Load existing byte data from cache [" + name + "] to create " + strType + " scope for " + pc.getApplicationContext().getName() + "/" + pc.getCFID()); return new IKStorageValue((byte[][]) val); } else if (val instanceof IKStorageValue) { ScopeContext.info(log, - "load existing data from cache [" + name + "] to create " + strType + " scope for " + pc.getApplicationContext().getName() + "/" + pc.getCFID()); + "Load existing data from cache [" + name + "] to create " + strType + " scope for " + pc.getApplicationContext().getName() + "/" + pc.getCFID()); return (IKStorageValue) val; } else { - ScopeContext.info(log, "create new " + strType + " scope for " + pc.getApplicationContext().getName() + "/" + pc.getCFID() + " in cache [" + name + "]"); + ScopeContext.info(log, "Create new [" + strType + "] scope for [" + pc.getApplicationContext().getName() + "/" + pc.getCFID() + "] in cache [" + name + "]"); } return null; } @@ -70,6 +70,7 @@ else if (existingVal != null) { cache.remove(key); } } + ScopeContext.info(log, "Store scope for [" + pc.getApplicationContext().getName() + "/" + pc.getCFID() + "] in cache [" + name + "]"); } catch (Exception e) { ScopeContext.error(log, e); diff --git a/core/src/main/java/resource/fld/core-base.fld b/core/src/main/java/resource/fld/core-base.fld index 6801064a3d..fb20d83c6d 100755 --- a/core/src/main/java/resource/fld/core-base.fld +++ b/core/src/main/java/resource/fld/core-base.fld @@ -12646,7 +12646,16 @@ You can find a list of all available timezones in the Lucee administrator (Setti string - + + + + SessionCommit + lucee.runtime.functions.system.SessionCommit + Force saving the session to storage, useful when sessionCluster is enabled. + + void + + diff --git a/test/tickets/LDEV2135.cfc b/test/tickets/LDEV2135.cfc index 9b26bb5862..752d99c55b 100644 --- a/test/tickets/LDEV2135.cfc +++ b/test/tickets/LDEV2135.cfc @@ -2,6 +2,9 @@ component extends="org.lucee.cfml.test.LuceeTestCase" labels="session" { function run( testResults , testBox ) { describe( "Test suite for LDEV-2135 using memory", function() { + + //beforeEach(function (currentSpec, data){ _beforeEach(currentSpec, data); }); + it( title='thread looses session variables - sessionCluster=false', body=function( currentSpec ) { test( {sessionCluster: false, sessionStorage: "memory"} ); }); @@ -12,21 +15,27 @@ component extends="org.lucee.cfml.test.LuceeTestCase" labels="session" { }); describe( title="Test suite for LDEV-2135 using redis", skip=skipRedis(), body=function() { + + //beforeEach(function (currentSpec, data){ _beforeEach(currentSpec, data); }); + it( title='thread looses session variables - redis- sessionCluster=false', body=function( currentSpec ) { test( {sessionCluster: false, sessionStorage: "redis"} ); }); - it( title='thread looses session variables - redis - sessionCluster=true', skip=true, body=function( currentSpec ) { + it( title='thread looses session variables - redis - sessionCluster=true', body=function( currentSpec ) { test( {sessionCluster: true, sessionStorage: "redis"} ); }); }); describe( title="Test suite for LDEV-2135 using memcached", skip=skipMemcached(), body=function() { + + //beforeEach(function (currentSpec, data){ _beforeEach(currentSpec, data); }); + it( title='thread looses session variables - memcached -sessionCluster=false', body=function( currentSpec ) { test( {sessionCluster: false, sessionStorage: "memcached"} ); }); - it( title='thread looses session variables - memcached -sessionCluster=true', skip=true, body=function( currentSpec ) { + it( title='thread looses session variables - memcached -sessionCluster=true', body=function( currentSpec ) { test( {sessionCluster: true, sessionStorage: "memcached"} ); }); }); @@ -44,7 +53,7 @@ component extends="org.lucee.cfml.test.LuceeTestCase" labels="session" { cfid: first.session.cfid, cftoken: first.session.cftoken }; - + // systemOutput("-- before secondRequest.cfm", true); var second = _InternalRequest( template : "#uri#/cfml-session/secondRequest.cfm", url: args, @@ -76,4 +85,9 @@ component extends="org.lucee.cfml.test.LuceeTestCase" labels="session" { private function skipMemcached(){ return (structCount(server.getTestService( "memcached" )) eq 0); } + + private function _beforeEach(currentSpec, data){ + systemOutput("", true); + systemOutput(currentspec, true); + } } \ No newline at end of file diff --git a/test/tickets/LDEV2135/cfml-session/secondRequest.cfm b/test/tickets/LDEV2135/cfml-session/secondRequest.cfm index 3613e86033..4dce77cfc4 100644 --- a/test/tickets/LDEV2135/cfml-session/secondRequest.cfm +++ b/test/tickets/LDEV2135/cfml-session/secondRequest.cfm @@ -1,4 +1,8 @@ - //systemOutput(session.toJson(), true); + if (!structKeyExists(session, "ldev3125")){ + //systemOutput(session.toJson(), true); + throw "key session.ldev3125 missing"; + } + //systemOutput(session.ldev3125.toJson(), true); echo(session.ldev3125.toJson()); \ No newline at end of file diff --git a/test/tickets/LDEV2135/cfml-session/testThreadSession.cfm b/test/tickets/LDEV2135/cfml-session/testThreadSession.cfm index b6065d5dd6..dc3eeda44c 100644 --- a/test/tickets/LDEV2135/cfml-session/testThreadSession.cfm +++ b/test/tickets/LDEV2135/cfml-session/testThreadSession.cfm @@ -1,4 +1,5 @@ + //systemOutput(url.toJson(), true); session.ldev3125 = {}; session.ldev3125.sessionCluster = url.sessionCluster; session.ldev3125.start = 'survived'; @@ -13,15 +14,17 @@ thread name="#name#" { try { ArrayAppend( session.ldev3125.threads, thread.name ); - sleep( 10 ); + // sleep( 10 ); // might need to be 1000 throw(type="blah", message="boom"); } catch(any e) { - writedump(session.ldev3125); + dump(session.ldev3125); } } } - + session.ldev3125.beforeJoin = 'hello'; thread action="join" name="#_threads.toList()#"; session.ldev3125.afterJoin = 'goodbye'; echo( session.ldev3125.toJson() ); + //systemOutput(session.toJson(), true); + sessionCommit(); \ No newline at end of file