Лучшая практика для создания потоков в веб-API - PullRequest
0 голосов
/ 11 октября 2018

У меня есть простой веб-API только с одним GET контроллером.Контроллер GET считывает данные XML и возвращает их в формате JSON.

API-интерфейс GET должен быть доступен каждую минуту, но в случае отсутствия запроса GET в течение более 1 минуты, мне нужно запуститьрезервное копирование данных (просто в формате XML ... ничего особенного).

My GET Api

        //GET api/
        public IHttpActionResult Get()
        {            
            try
            {
                //Read XML
                XDocument xDoc = XDocument.Load(@"D:\myfile.xml");


                //Convert XML data into JSON string
                string jsonStr = JsonConvert.SerializeXNode(xDoc);
                JObject json = JObject.Parse(jsonStr);

                return Ok(json);
            }
            catch (Exception ex)
            {
                return NotFound();
            }                     
        }

Образец XML:

<CurrentStatus>
    <Time Stamp= "20181011133631244">
        <price>12</price>
        <amount>100</amount>
    </Time>
</CurrentStatus>

Образец резервной копии в XML:

<CurrentStatus>
    <Time Stamp= "20181011133631244">
        <price>12</price>
        <amount>100</amount>
    </Time>
    <Time Stamp= "20181011133633354">
        <price>11</price>
        <amount>120</amount>
    </Time>
    <Time Stamp= "20181011133633204">
        <price>15</price>
        <amount>90</amount>
    </Time>
</CurrentStatus>

Моя плановая логика: Я планирую объявить static переменную _lastAccessedTimestamp, который будет контролироваться отдельным потоком.Если currentTime - _lastAccessedTimestamp> 1 min, тогда начните резервное копирование данных.

Вопрос: Хорошая практика для реализации потоков в Web API для этого типа сценария (или любого другого лучшего варианта)?

PS: Веб-служба будет работать на локальном сервере IIS.

Ответы [ 3 ]

0 голосов
/ 11 октября 2018

После каждого запроса я бы установил / сбросил таймер на 1 мин.Наличие переменной, которую вы опрашиваете из другого потока, неэффективно, и это вызывает другие проблемы.

Более того, вы можете использовать правильную библиотеку обработки заданий (например, Hangfire - https://www.hangfire.io/)), чтобы вы могли просто запланировать задание (через 1 минуту) и перепланировать его после каждого запроса, в случае, если новыйприходит запрос.

Помните, что IIS может остановить ваш процесс в любое время, возможно, вы захотите разобраться в этом. http://docs.hangfire.io/en/latest/deployment-to-production/making-aspnet-app-always-running.html

Для реализации вы можете использовать промежуточное ПО / фильтр, которыйделает это в конце каждого запроса автоматически. Нет необходимости добавлять это в контроллер. Также проще добавить несколько контроллеров без дублирования кода.

0 голосов
/ 11 октября 2018

Я бы сделал это, используя System.Timers.Timer.Далее читаем здесь -> Класс времени

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

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

 public class TimerService : ITimerService
{
    private readonly System.Timers.Timer _timer;
    private  DateTime _startTime = DateTime.Now;
    private double _timerSettings;

    public TimerService()
    {
      _timer = new System.Timers.Timer
        {
            AutoReset = true,
            Interval = 60000,
        };
        _timer.Elapsed += (sender, args) =>
        {
           //Backup Data method here
            _startTime = DateTime.Now;
        };
    }

    public double GetTimerInterval()
    {
        return _timer.Interval;
    }

    public void StopTimer()
    {
        if (_timer == null)
        {
            throw new ApplicationException("Timer not primed.");
        }
        _timer.Stop();
    }

    public void StartTimer()
    {
        if (_timer == null)
        {
            throw new ApplicationException("Timer not primed.");
        }
        _startTime = DateTime.Now;
        _timer.Start();
    }
}

При запуске приложения вы должны отключить таймер, через каждую минуту оно начнет выполнять резервное копирование данных.Из-за AutoReset = true.

Теперь просто сбросьте таймер в вашем контроллере

    [Route("api/[controller]/[action]")]
public class XmlController : Controller
{
    private readonly ITimerService _timerService;

    public XmlController(ITimerService timerService)
    {
        //Injected in
        _timerService = timerService;
    }

    [HttpGet]
    public IActionResult ProccessXML(object someXMLObject)
    {
        _timerService.StopTimer();
        SomeMethodWithXml(someXMLObject)
        //Reset Timer
        _timerService.StartTimer();
        return Ok();
    }


}
0 голосов
/ 11 октября 2018

Вы можете использовать что-то вроде Hangfire для запуска задачи, и тогда эта задача может быть обработана чем-то.Это может быть консольное приложение, другое веб-приложение, функция Azure, что угодно.Дело в том, что это внешнее по отношению к вашему основному веб-приложению.Затем вы можете немедленно вернуться, не дожидаясь, пока все закончится.Вы также можете использовать что-то вроде SignalR и веб-работников для отправки обновлений статуса клиенту.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...