Подтвердить что ты не робот

Как ограничить использование метода на количество времени?

Это должно быть тривиально, но я просто не могу пройти через это. Я должен ограничить количество заданий (например, соединения, отправленные сообщения или клики на кнопке) за количество времени. Так, например, Я могу отправить 1000 писем в час.

Как я могу сделать это в С#? Я не знаю и не волнует, сколько времени займет каждая операция. Я просто хочу убедиться, что за последний час будет выполнено только 1000.

4b9b3361

Ответ 1

 class EventLimiter
 {
    Queue<DateTime> requestTimes;
    int maxRequests;
    TimeSpan timeSpan;

    public EventLimiter(int maxRequests, TimeSpan timeSpan)
    {
        this.maxRequests = maxRequests;
        this.timeSpan = timeSpan;
        requestTimes = new Queue<DateTime>(maxRequests);
    }

    private void SynchronizeQueue()
    {
        while ((requestTimes.Count > 0) && (requestTimes.Peek().Add(timeSpan) < DateTime.UtcNow))
            requestTimes.Dequeue();
    }

    public bool CanRequestNow()
    {
        SynchronizeQueue();
        return requestTimes.Count < maxRequests;
    }

    public void EnqueueRequest()
    {
        while (!CanRequestNow())               
            Thread.Sleep(requestTimes.Peek().Add(timeSpan).Subtract(DateTime.UtcNow));
            // Was: System.Threading.Thread.Sleep(1000);

        requestTimes.Enqueue(DateTime.UtcNow);
    }
 }

Ответ 2

Предполагая окно календарного часа:

Поддерживать список действий, выполняемых.

Каждый раз, когда вы хотите сделать свое действие, удалите все в списке не в течение часа.

Если число меньше 1000, выполните действие и добавьте запись в список.


Предполагая ежечасно:

Создайте прокси-метод и переменную, которая увеличивается для каждого действия и уменьшается до нуля в течение часа.

Сделайте свое действие, если счетчик равен < 1000.

Ответ 4

Вы также можете рассмотреть возможность хранения {действия, времени, пользователя} информации в базе данных и получить количество действий за последний час fomr БД (или аналогичного сохраняемого хранилища), если вам необходимо обработать перезапуск/сбой пула приложений. В противном случае умный пользователь может обойти вашу защиту в памяти при перегрузке вашего сервера.

Ответ 5

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

  • Если счет больше лимита, вы отказываетесь от запроса
  • Если дата старше часа, вы reset счетчик и установите новую дату создания
  • Если дата правильная и счетчик находится под лимитом, вы увеличиваете счетчик

Только в двух последних случаях запрос выполняется.

Ответ 6

Вышеупомянутое решение выглядело отлично. Вот моя урезанная версия:

public class EmailRateHelper
{
    private int RequestsPerInterval = 30;
    private Queue<DateTime> History = new Queue<DateTime>();
    private TimeSpan Interval = new TimeSpan(0, 1, 0);

    public EmailRateHelper() { }
    public EmailRateHelper(int RequestsPerInterval, TimeSpan Interval)
    {
        this.RequestsPerInterval = RequestsPerInterval;
        this.Interval = Interval;
    }

    public void SleepAsNeeded()
    {
        DateTime _Now = DateTime.Now;
        History.Enqueue(_Now);
        if (History.Count >= RequestsPerInterval)
        {
            var _Last = History.Dequeue();                
            TimeSpan Difference = _Now - _Last;
            if (Difference < Interval)
                System.Threading.Thread.Sleep(Interval - Difference);
        }
    }
}