2015-06-21 1 views
1

Я хочу создать систему, похожую на stackoverflow отзыв особенность. То есть:Как создать систему назначения задач?

Задачи n, которые должны назначаться пользователям (количество пользователей неизвестно). В одно время одна задача должна назначаться не более чем одному пользователю, другим пользователям не должна назначаться одна и та же задача.

Например, n = 8, если один пользователь вводит систему по умолчанию, назначьте ему 3 задания.

  • В 17:00, Том входит в систему и получить задачи 1, 2, 3.
  • В 17:01, Джим входит в систему и получить задачи 4, 5, 6.
  • В 17 : 02, Джерри входит в систему и получает задания 7, 8.
  • В 17:03 Боб входит в систему и не получает никакой задачи.
  • В 17:05 Том выполнил задание 1, 2 и покинул систему.
  • В 17:06, Боб входит в систему снова и получить задание 3.

Предположим, что я использую базу данных для хранения задач информации.

Мое решение состоит в том, что, когда задачи 1, 2, 3 назначены Тому, удалите 3 записи из БД и сохраните их в памяти. Тогда другие не получат 3 записи. Когда Том покинет систему, снова добавьте свои завершенные задания и незавершенные задания в БД (с статусом задачи «завершено» или «незавершенным»).

Хотя недостатком является то, что записи хранилища в память не являются на 100% безопасными, если система разбилась, может возникнуть проблема с данными.

Может ли кто-нибудь знать, как конструкции штабеля отзыв особенность? Или поделиться другими решениями? Мне интересно, хорошо ли в этом прецеденте SELECT ... FOR UPDATE.

+0

Это зависит от того, как вы определяете «войти/выйти из системы». Простой подход: во время каждого запроса вы предполагаете, что пользователь «входит в систему». Если пользователь уже назначил задачи, все в порядке. Если есть открытые задачи, назначьте некоторые задачи этому пользователю (т. Е. Обновите задачу в db и запомните пользователя и временную метку), если у пользователя не будет достаточно назначенных задач. Если пользователь выйдет из системы или не был замечен некоторое время, вы можете удалить пользователя и его временную метку из таблицы задач. Таким образом, все, что вам нужно сделать сейчас, это: обновить задачи и их назначения во время каждого запроса. –

ответ

1

Что вам нужно реализовать, это стек FIFO или простая очередь. В Oracle лучше всего (если вы не хотите реализовать реальную очередь с AQ) для такой вещи - SELECT ... FOR UPDATE с предложением SKIP LOCKED. SKIP LOCKED позволяет легко управлять стеком с несколькими пользователями.

Вот простой интерфейс:

create or replace package task_mgmt is 

    function get_next_task return tasks.id%type; 

    procedure complete_task (p_id in tasks.id%type); 

    procedure release_task (p_id in tasks.id%type); 

end task_mgmt; 
/

Это реализация скелетная:

create or replace package body task_mgmt is 

    function get_next_task return tasks.id%type 
    is 
     return_value tasks.id%type; 
     cursor c_tsk is 
      select id 
      from tasks 
      where status = 'open' 
      order by date_created, id 
      for update skip locked; 

    begin 
     open c_tsk; 
     fetch c_tsk into return_value; 
     update tasks 
     set status = 'progress' 
      , assigned = user 
     where current of c_tsk; 
     close c_tsk; 
     return return_value; 
    end get_next_task; 

    procedure complete_task (p_id in tasks.id%type) 
    is 
    begin 
     update tasks 
     set status = 'complete' 
      , date_completed = sysdate 
     where id = p_id; 
     commit; 
    end complete_task; 

    procedure release_task (p_id in tasks.id%type) 
    is 
    begin 
     rollback; 
    end ; 

end task_mgmt; 
/

Обновление статуса, когда пользователи выскакивает стек создает блокировку. Из-за предложения SKIP LOCKED следующий пользователь не увидит эту задачу. Это намного чище, чем удаление и повторная установка записей.

Вот некоторые данные:

create table tasks (
    id number not null 
    , descr varchar2(30) not null 
    , date_created date default sysdate not null 
    , status varchar2(10) default 'open' not null 
    , assigned varchar2(30) 
    , date_completed date 
    , constraint task_pk primary key (id) 
    ) 
/

insert into tasks (id, descr, date_created) values (1000, 'Do something', date '2015-05-28') 
/
insert into tasks (id, descr, date_created) values (1010, 'Look busy', date '2015-05-28') 
/
insert into tasks (id, descr, date_created) values (1020, 'Get coffee', date '2015-06-12') 
/

Давайте поп!Вот Session один:

SQL> var tsk1 number; 
SQL> exec :tsk1 := task_mgmt.get_next_task ; 

PL/SQL procedure successfully completed. 

SQL> print :tsk1 

     TSK1 
---------- 
     1000 

SQL> 

Между тем в Сессия два:

SQL> var tsk2 number; 
SQL> exec :tsk2 := task_mgmt.get_next_task ; 

PL/SQL procedure successfully completed. 

SQL> print :tsk2 

     TSK2 
---------- 
     1010 

SQL> 

Назад в Session один:

SQL> exec task_mgmt.complete_task (:tsk1); 

PL/SQL procedure successfully completed. 

SQL> exec :tsk1 := task_mgmt.get_next_task ; 

PL/SQL procedure successfully completed. 

SQL> print :tsk1 

     TSK 
---------- 
     1020 

SQL> 

Основной недостаток этого подхода состоит в том, что оно требует, чтобы пользователи поддерживали сеансы с состоянием, пока они работают на e задача. Это не так, тогда вам нужен API, в котором get_next_task() является дискретной транзакцией и забывает о блокировке.


Кстати, это, вероятно, лучше, чтобы пользователи могли захватить задачу, а не назначать их через триггер входа в систему (или что вы имеете в виду под «Том входит в систему и получить задачи 1, 2, 3.») , Задачи вытягивания - это то, как работает очередь SO Review.

Кроме того, просто назначьте одну задачу за раз. Таким образом, вы можете получить эффективное распределение работы. Вы хотите избежать ситуации, когда Том имеет три задачи на своей тарелке, один из которых он не собирается завершать, и Боб ничего не может сделать. То есть, если вы не Боб.

+0

Спасибо, 'select ... for update skip locked' действительно полезен в этом случае! – coderz