Как использовать базу данных для управления семафором?

Если несколько экземпляров одного и того же кода работают на разных серверах, я хотел бы использовать базу данных, чтобы гарантировать, что процесс не запускается на одном сервере, если он уже запущен на другом сервере.

Я, вероятно, мог бы придумать некоторые работающие команды SQL, которые использовали бы обработку транзакций Oracle, защелки или что-то еще, но я бы предпочел найти что-то, что было проверено и верно.

Несколько лет назад разработчик, который был мастером SQL, имел единственную транзакцию SQL, которая брала семафор и возвращала истину, если она его получила, и возвращала ложь, если она ее не получала. Затем, в конце моей обработки, мне нужно будет запустить еще одну транзакцию SQL, чтобы освободить семафор. Было бы здорово, но я не знаю, может ли семафор, поддерживаемый базой данных, иметь тайм-аут. Тайм-аут был бы огромным бонусом!

РЕДАКТИРОВАТЬ:

Вот какие могут быть некоторые рабочие команды SQL, но без тайм-аута, за исключением взлома задания 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.
---------------------------------------------------------------------
7
задан Dale 2 February 2012 в 17:43
поделиться