My current application is using single instance of an object as a global variable for many of the main components, which I understand is considered inferior to using dependency injection.
I wish to make my applications open source in the future, but first I want to refactor the code to use the most recommended techniques for team collaboration so that other developers will be able to change my source code more easily.
Example of a shared resource: In the CFML language, you have the Server scope, which is shared memory that is available to any request for the entire server instance.
Here is my new design concept for managing changes to the Server scope:
Create a single instance of component named ServerMemoryManager which provides an interface for writing and reading to the server scope.
Any other code that needs to access the server scope will be injected with a reference to the single instance of the ServerMemoryManager via an init() function or a setServerMemoryManager() function.
Whenever a component reads/writes data to the ServerMemoryManager object, it will be able to internally lock the server scope so that no 2 threads can simultaneous write to the same piece of memory in the server scope.
Is this the best way to manage a shared resource (shared memory, filesystem, etc) that requires locking in order to be thread-safe?
Please describe any additional methods that can be used to manage a shared resource that requires locking during certain read/write operations which are considered best practices.
Edit: Based on the accepted answer, instead of locking scope="server", I will use named locks and manage the shared resources with more fine-grained locking. This may allow using multiple objects to manage the shared resources assuming they are all managing different keys in shared memory or files in the filesystem. For example, one application could have its own unique key or directory assigned to it so that it wouldn't conflict with another application trying to change a shared resource.
Edit2: I found I could use a single component named scope.cfc for each scope if I pass the scope into the init function when I create the object. I am now using fine-grained named locks. Let me know if it can be improved. The actual revised code now looks like this (I excluded the code for read, delete, clear). It also doesn't seem that it is required to have a single instance of the scope.cfc component anymore.
<cfcomponent>
<cfscript>
variables.scope=false;
variables.scopeName=false;
</cfscript>
<cffunction name="init" access="public" output="no" returntype="scope">
<cfargument name="scope" type="struct" required="yes">
<cfargument name="scopeName" type="string" required="yes">
<cfscript>
variables.scope=arguments.scope;
variables.scopeName=arguments.scopeName;
return this;
</cfscript>
</cffunction>
<cffunction name="write" access="public" output="no" returntype="boolean">
<cfargument name="key" type="string" required="yes">
<cfargument name="value" type="any" requires="yes">
<cfargument name="timeout" type="numeric" required="no" default="10">
<cftry>
<cflock type="exclusive" name="zcore-#variables.scopeName#-scope-#arguments.key#" timeout="#arguments.timeout#" throwontimeout="yes">
<cfscript>
variables.scope[arguments.key]=arguments.value;
</cfscript>
</cflock>
<cfcatch type="lock"><cfreturn false></cfcatch>
</cftry>
<cfreturn true>
</cffunction>
</cfcomponent>
** Edit3:** I tested the performance of reading from server scope through a component method like this and found it to be 20 times slower then reading the server scope directly when using a read only lock and 4 times slower without a lock. The overhead of an extra function call hundreds or thousands of times per request will be too slow. Tests done on Railo 3.3.x.
I prefer to build a large object in a non-public request and then set a single shared memory scope key then try to write an incomplete object to the scopes. Example:
<cfscript>
ts=structnew();
ts.largeObject=buildLargeObject();
server.cachedObject=ts;
</cfscript>
This lets you avoid locking across the entire application when you only write complete objects to shared memory since updating a single struct key is thread-safe. However, when you build the large object on startup, you need to be sure it is locked until that object is fully created.
I'm going to make the scope variable become directly readable by using the this scope instead of variables scope in the init function to avoid slowing down the application.
CFLOCK only prevents code from executing if every occurrence is locked the same way.
For example:
page1.cfm
<cflock type="exclusive" scope="server" timeout="10" >
<cfset application.xyz = 'abc'>
</cflock>
page2.cfm
<cfset application.xyz = '123'>
Page2.cfm is going to negate any locks you have on page1.cfm if page2 runs the same time page1 does. That said, it's good that you are locking inside your cfc so that each object doesn't have to be locked.
However, locking every occurrence isn't enough. The following won't do much good either.
page1.cfm
<cflock type="exclusive" scope="server" timeout="10" >
<cfset application.xyz = 'abc'>
</cflock>
page2.cfm
<cflock type="exclusive" scope="server" timeout="10" >
<cfset application.xyz = '123'>
</cflock>
This will halt the processing for every request of page1 and page2 but will not protect application.xyz on page1 from changes made to application.xyz on page2. To do this you need to give your locks a "name".
Locks name. Mutually exclusive with the scope attribute. Only one
request can execute the code within a cflocktag with a given name at a
time. Cannot be an empty string.
Permits synchronizing access to resources from different parts of an
application. Lock names are global to a ColdFusion server. They are
shared among applications and user sessions, but not clustered
servers.
Because you are creating multiple instances of your object, I believe serverMemoryManagerObject could interfere with serverMemoryManagerObject2 unless you name your lock.
Here is some more information about locking dos and don'ts
Locking code with cflock
CFLock And Negative Outcomes Think It Through
CFMythbusters - Countering Some Conventional Wisdom
Related
I've started with SI and kind of stuck right now as we want to use SI in one of our existing project avoiding changes where we can.
A bean which we would be using as a service activator accepts an constructor argument of a java object.
that object is in the payload but then I'm unable to set it using inner bean usage of service-activator
<service-activator input-channel="ADMIN_TEST_CONNECTION" method="testConnection">
<beans:bean class="mypackage.request.AdminRequestProcessor">
<beans:constructor-arg value="payload"/>
</beans:bean>
</service-activator>
it's complaining about Could not convert argument value of type [java.lang.String] to required type.
Please help in how to access payload and set it as an constructor argument.
If I go via non- constructor arg route and change existing java object then it works with this call in the service activator
expression="#bean.testConnection(payload)"/>
but I don't wish you to change the existing java code until there is no other way.
I think you don't have choice unless change something or add code around existing.
Service-Activator performs its functionality against each incoming message in the input-channel. And that functionality is exactly method invocation where Message is used as a context for method arguments.
Not sure what you are going to do with that payload, but that doesn't look correct to use statefull object like your AdminRequestProcessor. Just don't forget that you may have many incoming message, but service-activator should be consistent.
Plus don't forget that <beans:bean> is singleton, so your AdminRequestProcessor is instantiated only once.
Looking to your sample I'd suggest something like this:
expression="new AdminRequestProcessor(payload).testConnection()"/>
If you really don't want to change anything in your code.
Everything rest you can find in the Reference Manual.
Is it a best practice to wrap the ServiceStack's JsonServiceClient within a using statement?
var client = new JsonServiceClient();
client.Post(request);
versus
using (var client = new JsonServiceClient())
{
client.Post(request);
}
Which one is the best?
JsonServiceClient implements IDisposable so best practise would be to use it with a using statement.
However there are scenarios whereby you need to the share an instance of the JsonServiceClient across multiple requests (Such as when you use cookie based sessions, as the cookies are contained in the instances cookie container), in which case you would use the client without a using statement, but ensure that your application calls the Dispose method of the client, when it no longer requires the client.
This answer by gdoron further explains the best practise regarding classes that implement IDisposable such as the JsonServiceClient and the reasoning behind it.
As a rule, when you use an IDisposable object, you should declare and instantiate it in a using statement. The using statement calls the Dispose method on the object in the correct way, and (when you use it as shown earlier) it also causes the object itself to go out of scope as soon as Dispose is called. Within the using block, the object is read-only and cannot be modified or reassigned.
The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler. The code example earlier expands to the following code at compile time (note the extra curly braces to create the limited scope for the object):
I hope that helps.
I have a application that sends out a few 100k emails each night, so to speed processing added some cfthreads.
This has caused some strange errors, and I've found that a variable created in one thread is being modified by another thread. From the documentation I've read, variables created in one thread should be visible only to that thread?
Made a simple test like so:
<cfthread
name="thread1"
action="run">
<cfsavecontent variable="local.template_body">
<cfinclude template="templates\6\2\bulletin_template.cfm">
</cfsavecontent>
<cfset tmpEmailBody = template_body>
</cfthread>
<cfthread
name="thread2"
action="run">
<cffile action="append"
file="C:\inetpub\error1.txt"
output="#tmpEmailBody#">
</cfthread>
The contents of "tmpEmailBody" successfully get written to the file.
The strange thing is if i remove the cfsavecontent section, and have:
<cfset tmpEmailBody = "test">, then the second thread raises and error that tmpEmailBody isnt defined, as I would expect.
Anyone know what's going on here?
I believe your running cfthread for the wrong purpose. It seems that the tmpEmailBody in thread 2 is dependent on thread1. You should not run dependent code in separate threads..
A better use of cfthread as pertaining to mailing may be
Thread1 {
select Emails from database where emails start from a-m
out your list of a-m
}
Thread 2 {
select Emails from database where emails start from n-z}
out your list n-z
}
Both of your threads run at the same time. The 2 queries can take place at the same time, but you cant save variables in 1 thread and hope that it matches up your call timing in another thread.
The variable tmpEmailBody is being created in the Variables scope, not in a scope that is limited to the thread. The threads will execute in random order and random times, so the error is caused because thread1 hasn't executed its last line before thread2 executes its first line.
All of the normal scopes are not thread safe when using cfthread (as opposed to being thread safe for ColdFusion request threads; aka page threads) If you want to make sure that a variable created/used in one thread is isolated from all other threads then you must use thread scoping. This is officially documented as Using thread data in the ColdFusion documentation.
I would have guessed that you were declaring tmpEmailBody outside of the two threads, but since changing the cfset to a static string gives the expected behaviour I would say there's an "issue" with cfsavecontent and it's writing to the Variables scope instead of thread-local scope, which should be filed as another scoping gotcha.
Since the ColdFusion documentation examples leave a bit to be desired I'll rewrite your code as if you wanted to pass the email body from one thread to the other. You've said this isn't your intended use, but it will show the various thread scopes. The following code copies values into different scopes when it doesn't need to, but done to hopefully make the different scopes more clear. And, as others have stated, the below task is a poor use of threads.
<cfthread
name="thread1"
action="run">
<cfset var template_body = "">
<cfsavecontent variable="template_body">
<cfinclude template="templates\6\2\bulletin_template.cfm">
</cfsavecontent>
<cfset thread.tmpEmailBody = template_body>
</cfthread>
<cfthread action="join" name="thread1" timeout="60">
<cfset Variables.tmpEmailBody = cfthread["thread1"]tmpEmailBody>
<cfthread
name="thread2"
action="run"
emailBody="#Variables.tmpEmailBody#">
<cffile action="append"
file="C:\inetpub\error1.txt"
output="#Attributes.emailBody#">
</cfthread>
Consistently, I am able to generate a Java Heap Space OutOfMemory exception with the following code on ColdFusion 9.01 (haven't tried earlier versions):
<cfset uuidGenerator = createObject("java", "java.util.UUID")>
<cfset transient = structNew()>
<cfloop from="1" to="100000" index="index">
<cfset transient[uuidGenerator.randomUUID().toString()] = true>
</cfloop>
The code above uses the Java UUID class because its faster than ColdFusion's. The structure itself does not exist after the request (i.e. it's not in some persistent scope such as application).
As a test, I generate a heap dump just after initializing the server. Then I run this code several times and see the tenured generation fill through jConsole. After, I run another heap dump. Using Eclipse Memory Analysis Tool's Leak report I can see one large object rooted on coldfusion.util.Key.
I'm asking here in hopes others have hit similar problem, and if so, what they've done to work around it.
Not an ideal solution, but until Adobe fix the memory leak internally you can get access to the private member ConcurrentHasMap on the coldfusion.util.Key object and manually clear it.
We have setup a scheduled task to execute this nightly and then do a GC immediately afterwards.
Compile this into a JAR file and put it somewhere in your ColdFusion class path.
import coldfusion.util.Key;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
class KeyEx
{
public KeyEx()
{
}
public void resetCache(Object k)
{
try
{
Field f = Key.class.getDeclaredField("keys");
f.setAccessible(true);
ConcurrentHashMap chm = (ConcurrentHashMap)f.get(k);
chm.clear();
}
catch (Exception ex)
{
System.out.println("ZOMG something went epically wrong!");
}
}
}
And then you can simply instantiate the new KeyEx object in coldfusion and call resetCache passing in the coldfusion.util.Key singleton.
<cfset keys = createObject("java", "coldfusion.util.Key") />
<cfset x = createObject("java", "KeyEx").init() />
<cfset x.resetCache(keys) />
These two example tests probably illustrate the problem a bit clearer:
-- MemoryLeak.cfm
<cfset transient = structNew() />
<cfset base = getTickCount() />
<cfloop from="1" to="10000" index="index">
<cfset transient[hash("#base##index#")] = true >
</cfloop>
<cfoutput>
Done
</cfoutput>
-- NoMemoryLeak.cfm
<cfset transient = structNew() />
<cfloop from="1" to="10000" index="index">
<cfset transient[hash("#index#")] = true >
</cfloop>
<cfoutput>
Done
</cfoutput>
Hit MemoryLeak.cfm on a CF 9.01+ box for 100 times and the memory leak is really obvious. Restart JVM and hit NoMemoryLeak.cfm as many times as you want, and the OldGen won't even notice it. I got up to 500,000 times before giving up.
I can't see OrangePips original bug# in the CF bug-base (looks like all old bugs went in the upgrade?), so I created a new one https://bugbase.adobe.com/index.cfm?event=bug&id=3119991 status currently confirmed & ToFix.
OK, so this is what I ended up doing to track down the root cause. Heap dumps were showing me that coldfusion.util.Key.keys was holding on to many objects in a ConcurrentHashMap of type coldfusion.util.Key after I ran a load test for awhile. So I figured out which .jar contained the .class - /lib/cfusion.jar - and decompiled it to see the source. What I saw is that it holds onto these references in a static private field whose keys are never removed.
Basically this object gets created every time a key never used before is inserted into a structure. So it's called from all over any ColdFusion application. I believe the intent is to facilitate speedups around lookups, case insensitivity, and comparison.
Accepting then that I cannot change code to fix the issue, as I'm sure it would violate a license agreement when used in a production environment, I did change code to help me understand why so many objects were being created in the first place. I basically added the following to the constructor:
try {
throw new RuntimeException();
} catch (Exception e) {
e.printStackTrace(System.out);
}
Then I compiled and put the changed class into cfusion.jar.
Fortunately, the stack trace generated includes .cfm file names and line numbers. I started CF from a command line (i.e. jrun.exe -start coldfusion) so I could see what was going to System.out easily and then kicked off my load test again. So the heuristic was finding what code was calling this a lot and potentially changing that.
This allowed me to quickly see a .cfm file that was being called with every request. So I can change that file to no longer create structure keys all the time and this has resulted in a much longer running VM. It doesn't fix the problem completely, but lowers memory consumption dramatically.
My goal is to have some way of declaring my service classes as transactional. I dont want to leave it as an explicit declaration in spring configuration. Many times in past we have created new services and forgot to declare transactions around them. Hence my intention is that if i have something like #TransactionalService custom annotation, it should do the following :-
1. provides transactional support
2. declares some default rules for transactional support as spring currently provides as shown below. But unlike spring, i would like the below to be part of my #TransactionService annotation.
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
Any advice would be valuable?
Sure, instead of creating a new annotation, you could just put your transactionnal services in the same package, and then your pointcut (only one for all you transactionnal services) will look like this :
<aop:config>
<aop:pointcut id="transactionnalServiceMethods" expression="execution(* x.y.transactionnalservice.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="transactionnalServiceMethods"/>
</aop:config>
The advice is the same as above :
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>