AWS Java Lambda local variables vs object variables - java

I am trying to find answer to a very specific question. Trying to go through documentation but so far no luck.
Imagine this piece of code
#Override
public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
Request request = parseRequest(input);
List<String> validationErrors = validate(request);
if (validationErrors.size() == 0){
ordersManager.getOrderStatusForStore(orderId, storeId);
} else {
generateBadRequestResponse(output, "Invalid Request", null);
}
}
private List<String> validate(Request request) {
orderId = request.getPathParameters().get(PATH_PARAM_ORDER_ID);
programId = request.getPathParameters().get(PATH_PARAM_STORE_ID);
return new ArrayList<>();
}
Here, I am storing orderId and storeId in field variables. Is this okay? I am not sure if AWS will cache this function and hence cache the field variables or would it initiate a new Java object for every request. If its a new object, then storing in field variable is fine but not sure.

AWS will spin up a JVM and instantiate an instance of your code on the first request. AWS has an undocumented spin down time, where if you do not invoke your Lambda again within this time limit, it will shut down the JVM. You will notice these initial requests can take significantly longer but once your function is "warmed up", then it will be much quicker.
So to directly answer your question, your instance will be reused if the next request comes in quick enough. Otherwise, a new instance will be stood up.
A simple Lambda function that can illustrate this point:
/**
* A Lambda handler to see where this runs and when instances are reused.
*/
public class LambdaStatus {
private String hostname;
private AtomicLong counter;
public LambdaStatus() throws UnknownHostException {
this.counter = new AtomicLong(0L);
this.hostname = InetAddress.getLocalHost().getCanonicalHostName();
}
public void handle(Context context) {
counter.getAndIncrement();
context.getLogger().log("hostname=" + hostname + ",counter=" + counter.get());
}
}
Logs from invoking the above.
22:49:20 hostname=ip-10-12-169-156.ec2.internal,counter=1
22:49:27 hostname=ip-10-12-169-156.ec2.internal,counter=2
22:49:39 hostname=ip-10-12-169-156.ec2.internal,counter=3
01:19:05 hostname=ip-10-33-101-18.ec2.internal,counter=1

Strongly not recommended.
Multiple invocations may use the same Lambda function instance and this will break your current functionality.
You need to ensure your instance variables are thread safe and can be accessed by multiple threads when it comes to Lambda. Limit your instance variable writes to initialization - once only.

Related

Data Leakage Using InheritableThreadLocal

I'm using a threadpool to run some tasks in my application. Each task contains an object called TaskContext, which looks pretty much like this:
public class TaskContext implements Serializable {
private static InheritableThreadLocal<TaskContext> taskContextTL = new InheritableThreadLocal<>() ;
private final String taskName ;
private final String user;
public TaskContext(String taskName, String user) {
this.taskName= taskName;
this.user = user ;
}
public String getTaskName() {
return taskName ;
}
public static synchronized TaskContext getTaskContext() {
return taskContextTL.get() ;
}
public static synchronized void setTaskContext(TaskContext context) {
taskContextTL.set(context) ;
}
}
I use InheritableThreadLocal because I need the task data to be inherited by children threads.
At the beginning of each task, I use the setTaskContext(new TaskContext(taskName, user)) method to set the task parameters, and before the task ends- I use: setTaskContext(null) to clear this data.
The problem is that for some reason, when the same thread runs a different task, and for that thread I use the getTaskContext().getTaskName() method, I don't get the current task name but some previous task name that this thread ran.
Why is this happening? Why does setting InheritableThreadLocal value to null doesn't clear the data? How it can be avoided?
Thanks a lot for the help
Update:
I found a source online that claims this: "calling set(null) to remove the value might keep the reference to this pointer in the map, which can cause memory leak in some scenarios. Using remove is safer to avoid this issue."
But not sure what it means...
The source that you found that claims "calling set(null) to remove the value might keep the reference to this pointer in the map, which can cause memory leak in some scenarios. Using remove is safer to avoid this issue." is https://rules.sonarsource.com/java/tag/leak/RSPEC-5164.
Although I don't fully understand why they claim this I trust the people from sonarsource.com enough to consider this claim valid.
More to the point of your question they also provide a fix for this problem. Adapted to your code fragment it means that you should not use setTaskContext(null) to remove the TaskContext but rather create a method
public static void clearTaskContext() {
taskContextTL.remove() ;
}
and use this method to remove the TaskContext.
Also note that I didn't make this method synchronized and also the synchronization in getTaskContext() and setTaskContext() is not needed. Since the TaskContext is stored in a ThreadLocal that is (as its name implies) local to a specific thread there can never be a synchronization issue with them

Private variable shares between objects

I have class that looks like
public class Sender {
private LoggingAdapter log = Logging.getLogger(this.toString());
private final ArrayList<CSAMessage> sentHistory = new ArrayList<>();
public void send(final CSAMessage message) {
doSend(message);
sentHistory.add(message);
}
private void doSend(CSAMessage message) {
//do send stuff
}
}
The problem is - when two instances of Sender class are called in same time, they share private sentHistory field. In logs it looks like
Sender1 send(...) was called, message was added to own sendHistory list
Sender2 send(...) was called, message was added to Sender1 sendHistory list
How is that posiible? I'm shure that Sender1 and Sender2 are different instances, they called from different threads, but call was made in same time.
I already tried to make variable 'volatile' - no result
This block gives no result too
private final ArrayList<CSAMessage> sentHistory;
{
sentHistory = new ArrayList<>();
}
Only synchronizing via class helps
public void send(final CSAMessage message) {
synchronized (Sender.class) {
doSend(message);
sentHistory.add(message);
}
}
But this will be performance bottleneck - many Senders must be able to work in same time. And why should i do so? Different instances must use it's own variables!
There are also log variable that has been declared same way, but logging variable not shared between objects, every Sender write logs from it's own name.
Marking the variable final and initializing it the way you did
private final ArrayList<CSAMessage> sentHistory = new ArrayList<>();
// ^^^^^ ^^^^^^^^^^^^^^^^^^^
makes it absolutely impossible for multiple instances to share the same ArrayList.
What remains possible, however, is for multiple ArrayLists to share the same instances of CSAMessage. In cases when shared CSAMessages are mutable, it is possible to create an illusion of sharing. For example, if CSAMessage has a link back to Sender which is set as part of a send call, making a change concurrently may present the message as if it were sent through a wrong sender.

How to make thread safe singleton class which can accepts parameter?

I am trying to make a class as ThreadSafe Singleton but somehow I am not able to understand how to make ThreadSafe Singleton class which can accepts parameter.
Below is the class which I am using from this github link which I am using currently to make a connection to Zookeeper -
public class LeaderLatchExample {
private CuratorFramework client;
private String latchPath;
private String id;
private LeaderLatch leaderLatch;
public LeaderLatchExample(String connString, String latchPath, String id) {
client = CuratorFrameworkFactory.newClient(connString, new ExponentialBackoffRetry(1000, Integer.MAX_VALUE));
this.id = id;
this.latchPath = latchPath;
}
public void start() throws Exception {
client.start();
client.getZookeeperClient().blockUntilConnectedOrTimedOut();
leaderLatch = new LeaderLatch(client, latchPath, id);
leaderLatch.start();
}
public boolean isLeader() {
return leaderLatch.hasLeadership();
}
public Participant currentLeader() throws Exception {
return leaderLatch.getLeader();
}
public void close() throws IOException {
leaderLatch.close();
client.close();
}
public CuratorFramework getClient() {
return client;
}
public String getLatchPath() {
return latchPath;
}
public String getId() {
return id;
}
public LeaderLatch getLeaderLatch() {
return leaderLatch;
}
}
And this is the way I am calling the above class -
public static void main(String[] args) throws Exception {
String latchPath = "/latch";
String connStr = "10.12.136.235:2181";
LeaderLatchExample node1 = new LeaderLatchExample(connStr, latchPath, "node-1"); // this I will be doing only one time at just the initialization time
node1.start();
System.out.println("now node-1 think the leader is " + node1.currentLeader());
}
Now what I need is if I am calling these two below methods from any class in my program, I should be able to get an instance of it. So I am thinking to make above class as a Thread Safe Singleton so that I can access these two methods across all my java program.
isLeader()
getClient()
How do I make above class as ThreadSafe singleton and then make use of isLeader() and getClient() across all my classes to see who is the leader and get the client instance..
I need to do this only at the initialization time and once it is done, I should be able to use isLeader() and getClient() across all my classes.. Is this possible to do?
// this line I will be doing only one time at just the initialization time
LeaderLatchExample node1 = new LeaderLatchExample(connStr, latchPath, "node-1");
node1.start();
This is more of Java question not Zookeeper stuff..
A singleton which requires a parameter is a bit of a contradiction in terms. After all, you'd need to supply the parameter value on every call, and then consider what would happen if the value was different to an earlier one.
I would encourage you to avoid using the singleton pattern at all here. Instead, make your class a perfectly normal one - but use dependency injection to provide a reference to a single configured instance to all your classes that need it.
That way:
The singleton nature isn't enforced, it's just a natural part of you only needing one reference. If later on you needed two references (e.g. for different Zookeeper instances for some reason) you can just configure the dependency injection differently
The lack of global state generally makes things much easier to test. One test might use one configuration; another test might use a different one. No singleton, no problem. Just pass the relevant reference into the constructor of the class under test.

Singleton Object in Java Web service

Good morning,
I am currently developing a java web application that exposes a web service interface. In order to keep a global object in memory, I use the following class as a Singleton:
public class SingletonMap {
private static final SingletonMap instance = new SingletonMap();
private static HashMap couponMap = null;
private static long creationTime;
private SingletonMap() {
creationTime = System.currentTimeMillis();
couponMap = new HashMap();
}
public static synchronized SingletonMap getInstance() {
return instance;
}
public static long getCreationTime() {
return creationTime;
}
}
I am using the above class in order to have the same instance of the HashMap for all the threads of the web service. The Web service class that maintains the SingletonMap object is the following:
#WebService()
public class ETL_WS {
private String TOMCAT_TEMP_DIR;
private final int BUFFER_SIZE = 10000000;
private static SingletonMap couponMap;
private static SingletonProductMap productCategoryMap;
private String dbTable = "user_preferences";
public ETL_WS() {
Context context = null;
try {
context = (Context) new InitialContext().lookup("java:comp/env");
this.TOMCAT_TEMP_DIR = (String) context.lookup("FILE_UPLOAD_TEMP_DIR");
}catch(NamingException e) {
System.err.println(e.getMessage());
}
public long getCouponMapCreationTime() {
return couponMap.getCreationTime();
}
}
The reason i have the method getCouponMapCreationTime() is to check that all the threads of the web service are accessing the same object. Is the above approach correct? How about performance overheads? Do you think I need the Singleton properties, or could I just use a static HashMap for all the threads? If I use a static HashMap, is it going to be garbage collected in case no thread is active?
Thank you for your time.
A JAX-WS web service is by itself a Singleton. This means that all the request will be handled using a single web service instance (like a Servlet).
So, any member of the class will be 'shared' between all the request. In your case, you do not need to make your members (i.e. couponMap) an static attributes.
Conclusion: Don't worry, all your threads (request) will be accessing the same 'couponMap'. Because you don't need the getCouponMapCreationTime anymore, I think that you can eliminate the SingletonMap abstraction and use directly a Map in your web service class.
But I have something very important to add. If several threads (request) will be accessing your Map you have to make it thread-safe!!! There are a lot of way to do this, but I will give an idea: Use a ConcurrentHashMap instead of a HashMap. This will make all your get(), put(), remove() operations thread-safe! If you need a larger scope you can use synchronized blocks, but please avoid synchronize methods because the scoop is too large and always synchronize over this object.
JAX-WS has its own patterns for creating singletons, you don't need to use static fields. You use the #Inject annotation into each service. See this blog post: http://weblogs.java.net/blog/jitu/archive/2010/02/19/jax-ws-cdi-java-ee-6-0 (but don't use #SessionScoped, use #Singleton)
Some other points:
HashMap isn't thread-safe, you need ConcurrentHashMap.
This catch(NamingException e) { System.err.println(e.getMessage()); is unhelpful. Rethrow it as a RuntimeException. You can't recover from it.
Don't worry about performance overhead at this stage. Measure it once you have something working.

how to invoke schedular every day

what i do is ,when i run first time a servlet (which is invoked from jsp) that while put an entry of that service,daily in conf file.i want to run a scheduler which will invoke program(servlet- which runs and send mail) for that service daily 10 .
below is the code i use to execute a task.but problem is when i stop the server ,the scheduler stops and nothing happens
public class Schedule
{
public static final String CONF_PATH = "../webapps/selen/WEB-INF/scheduling.properties";
public static Properties schProps = null;
public static FileInputStream sis = null;
public static long period;
public static Timer timer = new Timer();
public static String servicename = null;
public static String keyValues = null;
public static String reValues[] = null;
public static String schedulingValue = null;
public static String service_url = null;
public static String browserlist = null;
public static String testType = null;
public static String mailCheacked = null;
public static String toaddr = null;
public static HttpServletRequest request = null;
public static HttpServletResponse response = null;
public static String serversURL = null;
public static String contextPath = null;
public static Date delay = null;
public void scheduleLoad(String serviceValue) throws Exception
{
try
{
schProps = new Properties();
sis = new FileInputStream(CONF_PATH);
schProps.load(sis);
servicename = SServlet.serviceName;
keyValues = schProps.getProperty(serviceValue);
reValues = keyValues.split(",");
String request = reValues[0];
String response = reValues[1];
schedulingValue = reValues[2];
service_url = reValues[3];
browserlist = reValues[4];
testType = reValues[5];
mailCheacked = reValues[6];
toaddr = reValues[7];
serversURL = reValues[8];
contextPath = reValues[9];
if(reValues[2].equals("Daily"))
{
Calendar cal =Calendar.getInstance();
cal.set(Calendar.HOUR,10);
cal.set(Calendar.MINUTE,20);
cal.set(Calendar.SECOND,0);
delay = cal.getTime();
period = 1000 * 60 * 60 * 24;
schedule();
}
else if(reValues[2].equals("Stop"))
{
stop();
}
}
catch(NullPointerException npe)
{
System.out.println("null point exception ");
}
finally
{
if(sis !=null)
{
sis.close();
}
}
}
public static void schedule()
{
MyTimerTask mt = new MyTimerTask(request,response,servicename,service_url,browserlist,mailCheacked,testType,schedulingValue,toaddr,serversURL,contextPath);
timer.schedule(mt,delay,period);
}
public static void stop()
{
timer.cancel();
}
}
class MyTimerTask extends TimerTask
{
public HttpServletRequest request;
public HttpServletResponse response;
public String servicename;
public String service_url;
public String browserlist;
public String mailCheacked;
public String testType;
public String schedulingValue;
public String toaddr;
public String serversURL;
public String contextPath;
public MyTimerTask(HttpServletRequest request,HttpServletResponse response, String servicename,String service_url,String browserlist,String mailCheacked,String testType,String schedulingValue,String toaddr,String serversURL, String contextPath)
{
this.request = request;
this.response = response;
this.servicename = servicename;
this.service_url = service_url;
this.browserlist = browserlist;
this.mailCheacked = mailCheacked;
this.testType = testType;
this.schedulingValue = schedulingValue;
this.toaddr = toaddr;
this.serversURL = serversURL;
this.contextPath = contextPath;
}
public void run()
{
SServlet sservlet = new SServlet();
sservlet.sServerloading(request,response,servicename,service_url,browserlist,mailCheacked,testType,schedulingValue,toaddr,false,1,serversURL,contextPath);
}
}
The JDK Timer runs in the JVM, not in the operating system. It's not CRON or Windows scheduler. So when you stop your server (Tomcat? JBoss? Glassfish?), you are effectivly stopping the JVM that the Timer lives in so of course it won't run any more. If you want a timer (scheduler) that runs independently of your server, you will have to start it in it's own JVM, either as a standalone java program using the java command or inside another server instance.
On a side note, if you're open to some critique, a small review of your code:
Avoid mixing static and non-static contexts if possible. Your Schedule class instance method scheduleLoad() makes heavy use of static member variables for statefull storage. Variables are either only used in the execution of a method (in which case they should be declared inside that method) or they are used to describe the state of an object (in which case they should be private instance members of the class) or they are global constants or immutable global variables (in which case they should be declared static final). Exceptions to these exist, but are less common.
Avoid declaring member variables public if they are not also final. Adhere to the JavaBean pattern, use getters and setters. If a variable is, in reality, a constant then it should be public static final.
Avoid using classes or parameters out of scope. For instance, your MyTimerTask uses HttpServletRequest and HttpServletResponse as member variables and method parameters. This makes no sense as MyTimerTask is not used in the scope of a servlet request (and will subsequently always be null, right?). Or, if that is indeed the case, if you are explicitly setting the static members of the Schedule in some servlet and then invoking scheduleLoad(), see my first point about improper use of static context. Your code would not be thread-safe and concurrent invocation of whichever servlet that uses the Schedule would produce unpredictable behaviour.
UPDATE:
It's hard to know where to start as I'm not sure what your level of expertise is in Java. If you are unfamiliar with how to execute stand-alone java applications, I would suggest having a go at some tutorials. Oracle has a bunch at http://download.oracle.com/javase/tutorial/. http://download.oracle.com/javase/tutorial/getStarted/index.html is a good place to start as it walks you through a very basic "hello world" type application with a main method and how to execute it using the java command, as well as some common mistakes and problems.
Once you've figured all that out, take a few minutes to figure out what your application should do, which resources it will require and if it needs to call any "external" systems. You mentioned that it should "execute a servlet to send mail". Does that mean that it has to call a specific servlet or is it just the sending mail that is really what you are after. In that case, maybe you can just move all the mail sending logic to your standalone program? If not, you will have to call the servlet using a http request (like a browser would). There are a number of existing frameworks for doing things like that. Apache HttpClient is a very popular one.
If you stop program it does not work. It is not a bug. It is a feature. BTW if you shutdown your computer nothing happens too :).
But If you questing is how to make my scheduled task more robust, e.g. how to make task to continue working when server stops and then starts again you have to persist somewhere the state of you scheduler, i.e. in your case the last time of task execution. You can implement this yourself: create special file and store the data there. You can use cross platform pure java Preferences API to do this: the data will be stored in file system in Unix and Registry in windows. you can save state in DB too.
But you can use other products that have already implemented this functionality. The most popular and well-known is Quartz.
But Quartz still need some java process to be up and running. If you want to be able to run your tasks even if no java process is running use platform dependent tools: cron tab for Unix and scheduler API for windows (it is accessible via VBScript, JScript, command line).
Unix has cron

Categories