|
[ sanchi @ 26.10.2010. 19:22 ] @
| Potrebno mi je da osiguram jedinstvenu instancu java aplikacije na masini.
Googlanjem sam pronasla vise resenja, ono koje mi se za sada najvise svidelo je koriscenjem Socketa, primer se moze videti na: http://java.itags.org/java-swing/1707/, (jedino sto ne bih koristila port 80, na drugom primeru sam videla da se koristi port 44331 npr.)
Da li ste se vec susretali sa slicnim problemom i kako ste ga resili, i da li vidite neke nedostatke resenja sa Socketom? |
[ misk0 @ 26.10.2010. 20:20 ] @
Ideja je dobra, ali nije garancija. Recimo da odaberes port na kojoj slusa neka druga aplikacija - neces je moci niti jednom pokrenuti. Trebala bi pri pokretanju kontrolisati koja vrsta aplikacije drzi taj port (trebala bi da mozes dobiti tu informaciju od OS-a) pa ako nije tvoja onda je pokreni na nekom drugom portu.
Mislim da bi dobra ideja bila zakljucavanje jednog fajla. Kao na linuxu .pid fajl. Fajl sadrzi broj procesa (a moze i bilo sta drugo), kad je aplikacija pokrenuta, drzis ga zakljucanim tako da mu druga app ne moze pristupiti (bar ga ne moze obrisati ili ponovo kreirati). Pri pokretanju aplikacije ga trazis - ukoliko ga nadjes, obrises ga (moze se desiti da zadnja pokrenuta instanca nije dobro ugasena pa ga je ostavila). Ukoliko ga ne mozes obrisati znaci da je jedna instanca vec pokrenuta i da ovu ugasis.
[ Dejan Lozanovic @ 26.10.2010. 21:27 ] @
Pa ja bih socket izbegao, bolje je koristiti file lock, generalno vecina servera na Unixima radi tako sto otvore eksluzivno neki file zatim u sadrzaj fajl-a upisu process ID same aplikacije. A na samom startovanju pitas se tipa da li taj fajl postoji ili ne i ukoliko postoji izadjes iz programa.
Druga varijanta je mozda jos elegantnija ali nazalost ne znam kako stoji stvar sa JVM-om koji nije Sun-ov(tj sad Oraclov) a to je da pozoves komandu Code: jps pa da procitas njen output i vidis da li je aplikacija startovana vise od jednog puta :), mana ove druge varijante je da tool vise nije podrzan i da ga mozda izbace u narednim verzijama jave. I da ne radi pod Win 98 i Win ME :) ali mislim da ova druga restrikcija nije strasna :)
[ iMac @ 26.10.2010. 23:00 ] @
Cao, sanchi. Dakle, ja bih to odradio na sledeci nacin:
napravio bih tabelu tbl_running
id|running
-----------
1 | 0
Pri startovanju aplikacije bih dohvatao ovaj jedan red i vrsio proveru, ako je 0, odradi update na 1 i startuj app. U suprotnom izbaci poruku da je app startovana i System.exit(0);
Toliko.
[ Goran Rakić @ 26.10.2010. 23:14 ] @
iMac, a onda vraćaš na nula kada gasiš program? I šta ako program pukne? Kako onda poništiš slog u tabeli? Ne koristi se flock bez razloga.
[ iMac @ 26.10.2010. 23:29 ] @
Samo mi pojasni "ako pukne program". Imas slucaj kada moras da obradis sve eventualne izuzetke -> u exceptionHandler-u odradis update. Ne vidim drugi problem, osim da iz nekog razloga ti se resetuje masina(mada ne znam kako ces ovo i s lock-ovima resiti, fajl je zakljucan). Bilo kako bilo, ne smatram da je moje resenje idealno ali moze da prodje. :)
[ iMac @ 26.10.2010. 23:45 ] @
Jos samo jedan dodatak za sanchi. Ovako bih ja definitivno odradio i mislim da moze da se pokriju sve varijante, ukljucujuci i prestanak struje. :d
Dakle, ostaje tabela tbl_running ili tbl_app_state (lepse zvuci :D :D)
id | state | reportTime
1 | 0 | 08-Oct-2088 12:00:00AM
E, sad, u aplikaciji ostaje standardno, kada se logujes ako je 0 onda ide update na 1 i update vremena na vreme startovanja app. Dalje, postavis timer da ti osvezava vreme na n minuta/sekundi (nemoj bas da ovo vreme bude kratko, smaras bazu bezveze).
Imas par slucaja ovde:
1. Ako je state 0 onda odmah ide update na 1 i update vremena
2. Ako je state 1 onda proveravas da li je razlika trenutnog vremena i vremena u bazi veca od periode osvezavanja stanja. Ako jeste, verovatno se desio prekid (prso javin process ili se restartovala masina) i onda dozvoljavas logovanje uz update vremenena, state ostaje 1.
3. Ako je state 1 a razlika trenutnog vremena i vremena u bazi manja od periode osvezavanja, onda ne dopustas startovanje app. E, sad, i ovde imas dve situacije. Ako je doslo do restarta, nakon njega neces odmah moci da pokrenes app vec ces morati da cekas da ta razlika postane veca od periode osvezavanja (po meni optimalno 10-ak minuta). Drugi slucaj da je zapravo starovana app i da ne mozes da je pokrenes.
[ Aleksandar Ružičić @ 27.10.2010. 00:29 ] @
po cemu se to razlikuje od istog tog pristupa sa lockom na neki fajl? isto mozes i fajlu da proveris create/access/modified timestamp. jedino sto u tvom slucaju moras da se kacis jos i na bazu...
najbolje resenje bi bilo kada bi koristila os mutex-e, preko JNI-a.. (nisam siguran dal to moze, ali bi trebalo da je izvodljivo)
[ Dejan Lozanovic @ 27.10.2010. 00:59 ] @
Citat: iMac: Samo mi pojasni "ako pukne program". Imas slucaj kada moras da obradis sve eventualne izuzetke -> u exceptionHandler-u odradis update. Ne vidim drugi problem, osim da iz nekog razloga ti se resetuje masina(mada ne znam kako ces ovo i s lock-ovima resiti, fajl je zakljucan). Bilo kako bilo, ne smatram da je moje resenje idealno ali moze da prodje. :)
Moze sam JVM da pukne i da ne stignes da uhvatis izuzetak. Drugi problem koji ja ovde vidim jeste nepotrebno dodavanje baze podataka, plus samo mi kazi sta ces da radis ako program ne trazi bazu podataka , znaci da uvodis bazu podataka samo zato da bi imao neki metod lokovanja, plus sto tvoje resenje ne moze da radi ovako kako si opisao u slucaju da imas recimo jedan SQL server i npr jedno 20-30 klijenata koji se konektuju na taj isti server.
Sam File je lokalan, programi koji rade na Unix-ima kao serveri napisu u samom fajlu process ID, pa ako naidjes na drugu instancu, jednostavno proveri na samom sistemu da li postoji program na tom proccessID-u i ako postoji da li je bas ta instanca u protivnom startuje program i upise svoj proccess ID u fajl.
Citat: Aleksandar Ružičić:
najbolje resenje bi bilo kada bi koristila os mutex-e, preko JNI-a.. (nisam siguran dal to moze, ali bi trebalo da je izvodljivo)
Os mutexi ne dozvoljavaju portabilnost arjitekture i operativnog sistema. Kao sto vec rekoh unix koristi kreiranje fajlova kao atomicnu operaciju.
http://www.exampledepot.com/egs/java.nio/SetFileLock.html
[Ovu poruku je menjao Dejan Lozanovic dana 27.10.2010. u 02:21 GMT+1]
[ Aleksandar Ružičić @ 27.10.2010. 01:40 ] @
Citat: Dejan Lozanovic: Os mutexi ne dozvoljavaju portabilnost arjitekture i operativnog sistema. Kao sto vec rekoh unix koristi kreiranje fajlova kao atomicnu operaciju.
to je tacno, ali nista te ne sprecava da u javi detektujes operativni sistem i da koristis odgovarajuci wrapper za os mutex.
e sad da to ne mora bas toliko da se komplikuje tu se slazemo, filelock je sasvim dovoljan..
[ iMac @ 27.10.2010. 07:27 ] @
@Lozanovic
Ako pukne VM ovo drugo resava. A za to da imas 30 klijenata koji pristupaju applikaciji bih uveo dodatnu kolonu user, jedinstvenu identifikaciju za sve te klijente. Vodio sam se time da svaka iole ozbiljna aplikacija ima nekid vid baze podataka. Dalje, u ovom tvom primeru imas lock = channel.tryLock(); Nakon toga pukne VM, restartuje se masina, kako god, ko ce da odradi lock.release(); ?
[ Dejan Lozanovic @ 27.10.2010. 10:09 ] @
Citat: iMac: @Lozanovic
Dalje, u ovom tvom primeru imas lock = channel.tryLock(); Nakon toga pukne VM, restartuje se masina, kako god, ko ce da odradi lock.release(); ?
Operativni sistem skida lockove sa fajlova , zatvara otvorene fajlove , oslobadja alociranu memoriju sa processa koji su prestali da se izvrsavaju. Tj ako nikad ne uradis release kad program prekine sa izvrsavanjem OS ce sam da uradi release. U slucaju da se resetuje operativni sistem, fajlovi nakon rebootovanja nece biti lockovani.
[ iMac @ 27.10.2010. 11:57 ] @
To je onda ok.
[ sanchi @ 27.10.2010. 13:51 ] @
Ok, hvala svima, iskoristicu file lock. Evo parceta koda koji sam takodje nasla na netu:
Code:
private static boolean lockInstance(final String lockFile) {
try {
final File file = new File(lockFile);
final RandomAccessFile randomAccessFile = new RandomAccessFile(
file, "rw");
final FileLock fileLock = randomAccessFile.getChannel().tryLock();
if (fileLock != null) {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
fileLock.release();
randomAccessFile.close();
file.delete();
} catch (Exception e) {
log.error(
"Unable to remove lock file: " + lockFile,
e);
}
}
});
return true;
}
} catch (Exception e) {
log.error("Unable to create and/or lock file: " + lockFile, e);
}
return false;
}
Copyright (C) 2001-2025 by www.elitesecurity.org. All rights reserved.
|