Как использовать базу данных для управления семафором? - PullRequest
7 голосов
/ 02 февраля 2012

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

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

Несколько лет назад разработчик, который был мастером SQL, имелединственная транзакция SQL, которая взяла семафор и вернула true, если он получил его, и вернула false, если он не получил его.Затем, в конце обработки, мне нужно выполнить еще одну транзакцию 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.
---------------------------------------------------------------------

1 Ответ

11 голосов
/ 02 февраля 2012

Вы должны заглянуть в DBMS_LOCK.По сути, он учитывает механизмы блокировки очереди, которые Oracle использует внутренне, за исключением того, что он позволяет вам определять тип блокировки «UL» (блокировка пользователя).Блокировки могут быть разделены или исключены, и запрос на снятие блокировки или преобразование блокировки из одного режима в другой поддерживает тайм-аут.

Я думаю, он будет делать то, что вы хотите.

Надеюсь, это поможет.

...