0

I have a java JAR file that is triggered by a SQL server job. It's been running successfully for months. The process pulls in a structured flat file to a staging database then pushes that data into an XML file.

However yesterday the process was triggered twice at the same time. I can tell from a log file that gets created, it looks like the process ran twice simultaneously. This caused a lot of issues and the XML file that it kicked out was malformed and contained duplicate nodes etc.

My question is, is this a known issue with Java JVM's spawning multiple instances of itself? Or should I be looking at sql server as the culprit? I'm looking into 'socket locking' or file locking to prevent multiple instances in the future.

This is the first instance of this issue that I've ever heard of.

More info:

The job is scheduled to run every minute. The job triggers a .bat file that contains the java.exe - jar filename.jar

The java program runs, scans a directory for a file and then executes a loop to process if the file if it finds one. After it processes the file it runs another loop that kicks out XML messages.

I can provide code samples if that would help.

Thank you,

Kevin

kevingreen
  • 1,541
  • 2
  • 18
  • 40
  • See http://stackoverflow.com/questions/177189/how-to-implement-a-single-instance-java-application – RichardOD Mar 08 '10 at 15:57
  • It sounds like yesterday is the first time the process took more than a minute to complete. Since it hadn't yet done whatever it does to mark the data as processed the second instance started a minute later thought it had work to do. The locking solutions suggested below should help you fix the issue permanently. As a temporary solution, increase the time between jobs to 5 or 10 minutes. – Chris Nava Mar 08 '10 at 17:44
  • Chris, thanks for the input. It was my understanding with Sql-Server jobs that it will wait until the job has completed before starting again. It runs at 1 minute on the hour, so if it runs at 05:01:00 and runs until 05:02:25 it will wait until 05:03:00 to run again. I intend to make us of one of the locking solutions listed here to solve the problem. I was hoping to understand the issue a little better. I have written many processes like this, and this is the first time I've seen the issue. – kevingreen Mar 08 '10 at 18:24

1 Answers1

3

It's not a Java problem. If you want the app to run alone, no copies, you should use the shell script or the java app to make and remove a lock somewhere.

You actually start multiple java's by starting more than 1 batch job with the same command. Windows nor Java can now that's not what you want. You could solve that by something like:

public static void main(String [ ] args)
{
   createLockIfNotExists();
   try {
       yourstuff;
   } finally {
     releaseLock();
   }
}
private static void createLockIfNotExists() throws MyLockAlreadyExists {
  // A bit tricky
  // check if LOCKFILE exists, if yes throw MyLockAlreadyExists
  // try to create LOCKFILE, can fail if at 1 ms earlier an other app created
  // that file, so an exception while creating also results in LockAlreadyExists
}

Are there good examples somewhere which handle this locking? Maybe in Apache Commons?

Here seems to be a functioning example for Windows.

You could also use the database to write your lock. Lock the locking table before you use it of course so no 2 processes write their lock at the same time, and afterwards read the lock record to check whether you actually got the lock. Something like pseudo code:

SELECT * FROM lock_table;

if locks.length > 0: someone else is running

LOCK lock_table;
INSERT INTO lock_table VALUES(my_pid);
UNLOCK lock_table;

SELECT pid FROM lock_table;

if pids.length > 1: what happened?
if pids[0] != my_pid: someone else got the lock 

A bit more juice and you also add not only the PID but also a timestamp, and check whether that timestamp is stale (too old).

extraneon
  • 23,575
  • 2
  • 47
  • 51
  • Thanks Richard and Extaneon. I'm going to try to implement the socket lock connection that is referenced in the article Richard links to. I might try the Lockfile technique if the socket method won't work. My biggest concern is I have several processes running via SQL server jobs executing Java. I will create lock processes for all of these if I have too, but I'm still wondering what caused the problem in the first place. My understanding was that it could only run once via the sql server job. But I might be missing something. Thanks! – kevingreen Mar 08 '10 at 16:07
  • I should also mention that I would up vote your answer, but I can't yet. I don't know if you care about the points, but I'd grant them if I could. – kevingreen Mar 08 '10 at 16:09
  • I concur that you need to use the presence of a file to lock the resource in case the two instances are running on different JVMs. Standard practice on Linux/UNIX is to put the process ID in that file so a human can find the process easier. – dj_segfault Mar 08 '10 at 16:12