Разрешить доступ к работе только одному пользователю одновременно - PullRequest
2 голосов
/ 09 июля 2019

У меня есть приложение ASP.NET Core, которое взаимодействует с веб-API.Существует бизнес-операция, включающая несколько шагов (выполните sth на одной странице, перейдите к следующей и следующей).Эта многошаговая операция выполняется в контексте одного элемента.

Итак, предположим, у вас есть список некоторых бизнес-объектов , и ваша задача - принять объект 3 из этого списка.Принятие является нашей многоступенчатой ​​операцией, и если я в данный момент принимаю объект 3 , никто больше не сможет войти в операцию принятия для объекта 3 .Когда я закончу операцию, она должна быть разблокирована.Надеюсь, что проблема понятна.

Мы не хотим очень трудоемкого решения, самая простая идея состояла в том, чтобы создать таблицу базы данных, которая указывает, когда пользователь начинает работу, сохраняет идентификатор объекта и идентификатор пользователя.и автоматически удалить себя, например, через 5 минут, если кто-то еще хочет получить доступ к операции, мы проверяем, заблокирована ли она для этого объекта.Но это отчасти хакерский и не очень чистый (что, если пользователь пойдет на кофе и продолжит работу через 10 минут?)

Я ищу лучший способ реализовать такое поведение и ценю любоеидеи

Ответы [ 2 ]

3 голосов
/ 09 июля 2019

Если бы я реализовал это поведение, я бы также использовал базу данных, но немного по-другому. Я создам таблицу из объектов ( объект 3 является одной из его строк), добавив столбец для UserId, логическое значение OnProcess (чтобы отметить, если объект включен или нет) и отметка времени для StartProcess.

Чтобы пользователь мог ввести операцию, выполните запрос, например:

UPDATE Objects SET UserId = <CurrentUser>, StartProcess = <NOW>, OnProcess = true
OUTPUT Object.Id
WHERE Object.Id == 3 AND 
    (
        OnProcess == false
        OR ( OnProcess == true AND UserId == <CurrentUser> )
        OR ( StartProcess <is more than 15 minutes ago>)
    )

отказ от ответственности: приведенный выше запрос не является исполняемым запросом, но он должен быть достаточно четким, чтобы понять, что он делает.

С запросом выше, Object.Id будет возвращено, когда:

  • объект не обрабатывается другим пользователем
  • объект обрабатывается самим CurrentUser, также сбрасывая StartProcess (какое-то скользящее поведение). Таким образом, если CurrentUser AFK в течение определенного времени (но не превышает пороговое время) и возвращается, он / она может с комфортом продолжить операцию
  • объект не обрабатывается в течение последних 15 минут. Это на самом деле порог, который я упоминаю в предыдущем пункте. Что касается того, как долго (15 минут в моем примере), это действительно зависит от вас.

Если для пользователя возвращается Object.Id, то он / она может ввести операцию.

0 голосов
/ 09 июля 2019

Вы ищете семафор. Ключевое слово lock является самым базовым из семафоров, но вы также можете использовать Semaphore / SemaphoreSlim, которые предоставляют возможность делать такие вещи, как ограничение скорости, тогда как lock будет буквально открывать по одной операции за раз. Тем не менее, ваша цель состоит в том, чтобы ставить по одной операции за раз, для определенного ресурса , что делает SemaphoreSlim лучшим выбором, в частности ConcurrentDictionary<string, SemaphoreSlim>.

Вам понадобится класс с единичным временем жизни (один экземпляр на всю жизнь приложения). Там вы добавите ивар:

private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphores = new ConcurrentDictionary<string, SemaphoreSlim>();

Затем вы добавите следующий код вокруг операции, которую вы хотите использовать:

var semaphore = _semaphores.GetOrAdd("object3", _ => new SemaphoreSlim(1, 1));
await semaphore.WaitAsync();

// do something

semaphore.Release();

"object3" там, очевидно, просто заполнитель. Вы захотите использовать все, что имеет смысл (идентификатор и т. Д.) - то, что однозначно идентифицирует конкретный ресурс, который вы получаете. Тогда он будет содержать операции только для этого конкретного ресурса, если на этом конкретном ресурсе уже существует операция. Другой ресурс получит свой семафор и, следовательно, свои ворота.

...