2012-02-02 8 views
7

Se più istanze dello stesso codice sono in esecuzione su server diversi, vorrei utilizzare un database per assicurarsi che un processo non viene avviato su un server, se è già in esecuzione su un altro server.Come si usa un database per gestire un semaforo?

Probabilmente potrei venire con alcuni comandi SQL utilizzabili che hanno utilizzato l'elaborazione delle transazioni Oracle, i latch o qualsiasi altra cosa, ma preferirei trovare qualcosa che sia stato provato e vero.

Anni fa uno sviluppatore che era un wiz SQL aveva una singola transazione SQL che prendeva il semaforo e restituiva true se lo otteneva e restituiva false se non lo otteneva. Poi alla fine del mio processo, avrei bisogno di eseguire un'altra transazione SQL per rilasciare il semaforo. Sarebbe bello, ma non so se è possibile che un semaforo supportato da database abbia un time-out. Sarebbe un enorme vantaggio avere un timeout!

EDIT:

Ecco quello che potrebbe essere alcuni comandi SQL praticabili, ma nessun timeout se non attraverso un hack job cron:

--------------------------------------------------------------------- 
--Setup 
--------------------------------------------------------------------- 
CREATE TABLE "JOB_LOCKER" ("JOB_NAME" VARCHAR2(128 BYTE), "LOCKED" VARCHAR2(1 BYTE), "UPDATE_TIME" TIMESTAMP (6)); 
CREATE UNIQUE INDEX "JOB_LOCKER_PK" ON "JOB_LOCKER" ("JOB_NAME") ; 
ALTER TABLE "JOB_LOCKER" ADD CONSTRAINT "JOB_LOCKER_PK" PRIMARY KEY ("JOB_NAME"); 
ALTER TABLE "JOB_LOCKER" MODIFY ("JOB_NAME" NOT NULL ENABLE); 
ALTER TABLE "JOB_LOCKER" MODIFY ("LOCKED" NOT NULL ENABLE); 

insert into job_locker (job_name, locked) values ('myjob','N'); 
commit; 

--------------------------------------------------------------------- 
--Execute at the beginning of the job 
--AUTOCOMMIT MUST BE OFF! 
--------------------------------------------------------------------- 
select * from job_locker where job_name='myjob' and locked = 'N' for update NOWAIT; 
--returns one record if it's ok. Otherwise returns ORA-00054. Any other thread attempting to get the record gets ORA-00054. 
update job_locker set locked = 'Y', update_time = sysdate where job_name = 'myjob'; 
--1 rows updated. Any other thread attempting to get the record gets ORA-00054. 
commit; 
--Any other thread attempting to get the record with locked = 'N' gets zero results. 
--You could have code to pull for that job name and locked = 'Y' and if still zero results, add the record. 

--------------------------------------------------------------------- 
--Execute at the end of the job 
--------------------------------------------------------------------- 
update job_locker set locked = 'N', update_time = sysdate where job_name = 'myjob'; 
--Any other thread attempting to get the record with locked = 'N' gets no results. 
commit; 
--One record returned to any other thread attempting to get the record with locked = 'N'. 

--------------------------------------------------------------------- 
--If the above 'end of the job' fails to run (system crash, etc) 
--The 'locked' entry would need to be changed from 'Y' to 'N' manually 
--You could have a periodic job to look for old timestamps and locked='Y' 
--to clear those. 
--------------------------------------------------------------------- 
+2

Per evitare scadenza manualmente i record, si può avere la serratura essere un timestamp. L'acquisizione del blocco imposta ora il timestamp. Per acquisire il blocco, la query per il blocco deve aggiungere una condizione WHERE locktime <(SYSDATE - timeToExpire). Quindi i fermi scadono automaticamente. – Glenn

+0

Grazie Glenn ... il timestamp invece di Y/N è una bella aggiunta a quanto sopra. – Dale

risposta

11

si dovrebbe guardare in DBMS_LOCK. In sostanza, consente i meccanismi di blocco dei messaggi di coda che Oracle utilizza internamente, tranne che consente di definire un tipo di blocco di "UL" (blocco utente). I blocchi possono essere mantenuti condivisi o esclusivi e una richiesta di blocco o conversione di un blocco da una modalità a un'altra supporta un timeout.

Penso che sarà fare quello che vuoi.

Spero che questo aiuti.

+0

Mi piace che questo abbia un timeout. Non ho mai usato DBMS_LOCK prima, e non sono proprio un fantino SQL, quindi potrebbe essere una dura battaglia per me farlo funzionare, hehe. – Dale

Problemi correlati