Как синхронизировать вызов метода между задачами в net core 3 - PullRequest
0 голосов
/ 01 марта 2020

В моем приложении у меня есть BackgroundService, который также включает следующий метод:

  • GetNumberAsyn c () получает «самую старую» запись из базы данных и обновляет свойства записи.

Этот метод вызывается из асинхронного c метода контроллера API, например:

[HttpGet]
[Route("GetNumber")]
public async Task<ActionResult<string>> GetNumber()
{
    return Ok(await _numberService.GetNumberAsync());
}

Боюсь, что при двух или более вызовах GetNumberAsyn c () происходит одновременно, тогда некоторые из них могут получить одну и ту же запись. Как этого избежать, ведь каждый вызов должен возвращать уникальную запись?

Код метода:

    internal async Task<string> GetNumberAsync()
    {
        var num = await _smsDbContext.ZadarmaPhoneNumbers
            .OrderBy(x => x.LockedTime)
            .FirstOrDefaultAsync();

        if(num != null)
        {
            num.LockedTime = DateTime.Now;
            num.SmsCode = "";

            _smsDbContext.ZadarmaPhoneNumbers.Update(num);

            await _smsDbContext.SaveChangesAsync();

            return num.Number;
        }

        return "";
    }

Спасибо.

1 Ответ

0 голосов
/ 01 марта 2020

Вот идея, как вы можете это реализовать.

Предположим, у вас есть таблица телефонов, как эта. Вы можете добавить LockedTime, чтобы добавить критерий времени.

create table phones (
  used bit default 0 not null,
  phone varchar(24) not null);

Выполните этот запрос, чтобы извлечь только один телефон, и он не будет возвращен дважды, поскольку он помечен как использованный.

update top(1) phones
set used = 1
output inserted.phone
where used = 0
;

Примечание что он работает на сервере MS SQL. Некоторые другие серверы SQL могут не иметь предложения вывода.

Если вы хотите вернуть номер в пул свободных номеров, вам просто нужно сбросить флаг used. Например, вы можете сделать это, проверяя временные критерии или любой другой, решая, что телефон становится свободным

update phones set used = 0 where LockedTime < @somedatetime

...