Несоответствующие значения класса ASP.NET Singleton - PullRequest
0 голосов
/ 26 ноября 2018

У меня есть особое требование, чтобы разрешить только 5 одновременный доступ к методу WebAPI (специфично для .NET 4.5) (как часть плана лицензирования).Когда 5 одновременных лимитов достигнут, webapi должен отклонить любые дальнейшие попытки от ЛЮБОГО пользователя.

Я создал класс Singleton для подсчета количества обращений к методу иуменьшит счетчик после выполненной обработки и выполнит проверку, если число> 5.

    [HttpGet]
    [Route("GetOrderStatus/{id}")]
    public async Task<string> GetOrderStatus(int id)
    {
        GlobalState state = GlobalState.Instance;
        string result;

        if (state.OrderStatus > 5)
        {
            Log.Debug("INVALID - state.OrderStatus: " + state.OrderStatus.ToString() + ", ID: " + id.ToString());
            return await Task.FromResult("INVALID");
        }
        else
        {
            state.OrderStatus++;
            Log.Debug("state.OrderStatus: " + state.OrderStatus.ToString() + ", ID: " + id.ToString());
            result = DoGetOrder(id);
            state.OrderStatus--;
        }

        return await Task.FromResult(result);
    }

    private string DoGetOrder(int OrderTypeId)
    {
        Thread.Sleep(5000);
        return "OK_" + OrderTypeId.ToString();
    }

Мой класс синглтона ниже.

public sealed class GlobalState
{
    private static readonly Lazy<GlobalState> lazy = new Lazy<GlobalState>(() => new GlobalState());

    public int OrderStatus { get; set; }
    public int PlaceOrder { get; set; }

    public static GlobalState Instance { get { return lazy.Value; } }
    private GlobalState()
    {

    }
}

Unit Test.

   using Flurl.Http;

   [TestMethod]
    public void GetOrderStatus_Returns_Valid()
    {
        StringBuilder sb = new StringBuilder();
        int success = 0;
        int failed = 0;

        Parallel.For(0, 100, i =>
        {
            string url = "http://localhost:61803/api/getorderstatus/" + i.ToString();

            var responseString = url.GetStringAsync().Result;
            sb.AppendLine(responseString + ", ");

            if (responseString.Contains("INVALID"))
            {
                failed++;
            }
            else
            {
                success++;
            }
        });
    }

Результаты теста неверны.Журнал воспроизводится ниже.

2018-11-26 10:00:29.431 +00:00 [DBG] state.OrderStatus: 2, ID: 0
2018-11-26 10:00:29.432 +00:00 [DBG] state.OrderStatus: 3, ID: 25
2018-11-26 10:00:29.434 +00:00 [DBG] state.OrderStatus: 4, ID: 50
2018-11-26 10:00:30.310 +00:00 [DBG] state.OrderStatus: 5, ID: 75
2018-11-26 10:00:31.311 +00:00 [DBG] state.OrderStatus: 6, ID: 1
2018-11-26 10:00:32.313 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 26
2018-11-26 10:00:33.311 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 27
2018-11-26 10:00:33.312 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 51
2018-11-26 10:00:34.308 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 28
2018-11-26 10:00:34.308 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 52
2018-11-26 10:00:34.310 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 76
2018-11-26 10:00:35.309 +00:00 [DBG] state.OrderStatus: 4, ID: 3
2018-11-26 10:00:35.309 +00:00 [DBG] state.OrderStatus: 5, ID: 34
2018-11-26 10:00:35.309 +00:00 [DBG] state.OrderStatus: 4, ID: 30
2018-11-26 10:00:36.309 +00:00 [DBG] state.OrderStatus: 5, ID: 54
2018-11-26 10:00:36.309 +00:00 [DBG] state.OrderStatus: 5, ID: 79
2018-11-26 10:00:36.309 +00:00 [DBG] state.OrderStatus: 6, ID: 77
2018-11-26 10:00:36.309 +00:00 [DBG] state.OrderStatus: 6, ID: 53
2018-11-26 10:00:36.311 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 2
2018-11-26 10:00:36.321 +00:00 [DBG] state.OrderStatus: 6, ID: 29
2018-11-26 10:00:37.309 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 5
2018-11-26 10:00:37.309 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 56
2018-11-26 10:00:37.311 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 7
2018-11-26 10:00:38.312 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 8
2018-11-26 10:00:39.310 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 57
2018-11-26 10:00:39.310 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 6
2018-11-26 10:00:39.310 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 10
2018-11-26 10:00:39.311 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 81
2018-11-26 10:00:39.312 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 9
2018-11-26 10:00:40.355 +00:00 [DBG] state.OrderStatus: 4, ID: 14
2018-11-26 10:00:40.356 +00:00 [DBG] state.OrderStatus: 5, ID: 4
2018-11-26 10:00:40.357 +00:00 [DBG] state.OrderStatus: 6, ID: 35
2018-11-26 10:00:40.357 +00:00 [DBG] state.OrderStatus: 6, ID: 36
2018-11-26 10:00:40.357 +00:00 [DBG] state.OrderStatus: 6, ID: 58
2018-11-26 10:00:40.359 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 18
2018-11-26 10:00:42.310 +00:00 [DBG] state.OrderStatus: 3, ID: 78
2018-11-26 10:00:42.310 +00:00 [DBG] state.OrderStatus: 3, ID: 84
2018-11-26 10:00:42.310 +00:00 [DBG] state.OrderStatus: 2, ID: 59
2018-11-26 10:00:42.311 +00:00 [DBG] state.OrderStatus: 4, ID: 31
2018-11-26 10:00:42.311 +00:00 [DBG] state.OrderStatus: 4, ID: 55
2018-11-26 10:00:42.313 +00:00 [DBG] state.OrderStatus: 5, ID: 37
2018-11-26 10:00:42.313 +00:00 [DBG] state.OrderStatus: 6, ID: 80
2018-11-26 10:00:43.313 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 11
2018-11-26 10:00:44.310 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 20
2018-11-26 10:00:44.310 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 12
2018-11-26 10:00:45.310 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 60
2018-11-26 10:00:45.310 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 13
2018-11-26 10:00:45.312 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 21
2018-11-26 10:00:45.312 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 19
2018-11-26 10:00:45.318 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 82
2018-11-26 10:00:45.320 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 39
2018-11-26 10:00:46.313 +00:00 [DBG] state.OrderStatus: 3, ID: 46
2018-11-26 10:00:46.313 +00:00 [DBG] state.OrderStatus: 4, ID: 64
2018-11-26 10:00:46.313 +00:00 [DBG] state.OrderStatus: 3, ID: 69
2018-11-26 10:00:46.314 +00:00 [DBG] state.OrderStatus: 5, ID: 22
2018-11-26 10:00:46.315 +00:00 [DBG] state.OrderStatus: 6, ID: 71
2018-11-26 10:00:46.315 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 61
2018-11-26 10:00:46.315 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 24
2018-11-26 10:00:46.315 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 44
2018-11-26 10:00:46.317 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 15
2018-11-26 10:00:46.321 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 85
2018-11-26 10:00:46.324 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 62
2018-11-26 10:00:46.324 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 87
2018-11-26 10:00:46.325 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 45
2018-11-26 10:00:46.327 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 16
2018-11-26 10:00:46.331 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 88
2018-11-26 10:00:46.331 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 65
2018-11-26 10:00:46.333 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 83
2018-11-26 10:00:46.336 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 40
2018-11-26 10:00:46.338 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 86
2018-11-26 10:00:46.338 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 23
2018-11-26 10:00:46.343 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 66
2018-11-26 10:00:46.345 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 63
2018-11-26 10:00:46.345 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 89
2018-11-26 10:00:46.345 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 17
2018-11-26 10:00:46.351 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 41
2018-11-26 10:00:46.352 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 67
2018-11-26 10:00:46.353 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 90
2018-11-26 10:00:46.355 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 42
2018-11-26 10:00:46.359 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 43
2018-11-26 10:00:46.359 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 68
2018-11-26 10:00:46.362 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 91
2018-11-26 10:00:46.365 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 92
2018-11-26 10:00:46.368 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 93
2018-11-26 10:00:46.371 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 94
2018-11-26 10:00:46.374 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 95
2018-11-26 10:00:46.377 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 96
2018-11-26 10:00:46.380 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 97
2018-11-26 10:00:46.383 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 98
2018-11-26 10:00:46.386 +00:00 [DBG] INVALID - state.OrderStatus: 6, ID: 99
2018-11-26 10:00:47.321 +00:00 [DBG] state.OrderStatus: 1, ID: 38
2018-11-26 10:00:47.321 +00:00 [DBG] state.OrderStatus: 1, ID: 32
2018-11-26 10:00:51.323 +00:00 [DBG] state.OrderStatus: -1, ID: 47
2018-11-26 10:00:51.323 +00:00 [DBG] state.OrderStatus: -2, ID: 72
2018-11-26 10:00:51.324 +00:00 [DBG] state.OrderStatus: 0, ID: 70
2018-11-26 10:00:52.326 +00:00 [DBG] state.OrderStatus: 0, ID: 33
2018-11-26 10:00:56.327 +00:00 [DBG] state.OrderStatus: -1, ID: 73
2018-11-26 10:00:56.331 +00:00 [DBG] state.OrderStatus: 0, ID: 48
2018-11-26 10:01:01.331 +00:00 [DBG] state.OrderStatus: -1, ID: 74
2018-11-26 10:01:01.335 +00:00 [DBG] state.OrderStatus: -1, ID: 49

Значение state.OrderStatus становится равным 6, для успеха и недействительным, а также становится отрицательным в журнале, и всегда не согласованным.

Пожалуйста, сообщите, что я делаю не так.

1 Ответ

0 голосов
/ 26 ноября 2018

Это просто проблема параллелизма.if (state.OrderStatus > 5) может быть оценено несколькими потоками как ложное, после чего все они увеличиваются с использованием state.OrderStatus++; (что само по себе имеет проблему чтения-записи).

Решение заключается в использовании Interlocked.Increment для таких сценариев (обратите внимание, что state.OrderStatus должно быть полем для компиляции этого кода, а не свойством):

int current = Interlocked.Increment(ref state.OrderStatus);

try
{
    if (current > 5)
    {
        Log.Debug("INVALID - state.OrderStatus: " + state.OrderStatus.ToString() + ", ID: " + id.ToString());
        return await Task.FromResult("INVALID");
    }
    else
    {
        Log.Debug("state.OrderStatus: " + state.OrderStatus.ToString() + ", ID: " + id.ToString());
        result = DoGetOrder(id);
    }
}
finally
{
    Interlocked.Decrement(ref state.OrderStatus);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...