views:

61

answers:

1

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

+3  A: 

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
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
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
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