Планирование асинхронных задач упрощается с помощью Actix Cron.

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

Что мы узнаем : —

  1. Настройка Actix-web.
  2. Добавление длительности для периодических задач.
  3. Добавление парсера cron для гибкости планирования.
  4. Выполнение операций с БД с помощью cronjobs.

Необходимые библиотеки :-

  • actix-web :- мощный, прагматичный и чрезвычайно быстрый веб-фреймворк для Rust
  • reqwest :- клиентская библиотека HTTP более высокого уровня
  • actix-rt :- однопоточная асинхронная среда выполнения на базе Tokio для экосистемы Actix
  • cron :- парсер выражений cron и проводник расписаний.
  • chrono :- Библиотека даты и времени для Rust

1. Настройка Actix-web

Инициализация проекта Rust

Запустите новый проект со следующим cargo new <file-name>.

Реализация базового actix-сервера

Давайте клонируем пример кода из официальной документации actix.

Добавьте зависимость в cargo.toml

....
[dependencies]
actix-web = "4"
....
Войдите в полноэкранный режим Выйти из полноэкранного режима

Напишем код для сервера actix.

use actix_web::{web, App, HttpServer};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .route("/hello", web::get().to(|| async { "Hello World!" }))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}
Вход в полноэкранный режим Выйти из полноэкранного режима

2. Добавление длительности для периодических задач.

use std::{collections::HashMap, time::Duration};
use reqwest;
use actix_rt::time;

// async function to get data from url using reqwest library

async fn get_ips() -> HashMap<String, String> {
    let resp = reqwest::get("https://httpbin.org/ip")
        .await.unwrap()
        .json::<HashMap<String, String>>()
        .await.unwrap();
    resp
}

async fn main() -> std::io::Result<()> {

  actix_rt::spawn(async {
      let mut interval = time::interval(Duration::from_secs(20));
      loop {
          interval.tick().await;
          let result = get_ips().await;
          println!("20 sec {:?}",result);
      }
  });
  ....
}
Вход в полноэкранный режим Выход из полноэкранного режима

Запутались?

Нет, не нужно путаться. Давайте попробуем разобраться в пошаговом коде.

actix_rt ()
Это однопоточная асинхронная среда выполнения на основе tokio для системы actix.

Однопоточность означает, что за один раз выполняется только одна команда.

actix_rt::spawn : Порождает будущее на текущем потоке как новую задачу. Если задача не ожидается немедленно, она может быть отменена с помощью JoinHandle::abort (при отмене отсоединяет текущий поток).

actix_rt::spawn(async move {}) : move позволит вам захватить переменную окружения закрытия.

Закрытия — это простые анонимные функции
которые могут храниться в переменной и не требуют аннотирования типов.

tokio time::interval : Создает новый интервал, который выдает интервал длительности. Первый тик завершается немедленно.

  • interval.tick() : Завершается при достижении следующего мгновения в интервале.

Duration::from_secs(20) : Создает новую Duration с введенным целым числом в секундах.

3. Добавление парсера cron для гибкости планирования.

use std::{collections::HashMap, time::Duration, str::FromStr};
use chrono::{Local, FixedOffset};
use cron::Schedule;
use reqwest;
use actix_rt::{self, time};

use actix_web::{web, App, HttpServer};

async fn get_ips() -> HashMap<String, String> {
    let resp = reqwest::get("https://httpbin.org/ip")
        .await.unwrap()
        .json::<HashMap<String, String>>()
        .await.unwrap();
    resp
}

#[actix_web::main] // or #[tokio::main]
async fn main() -> std::io::Result<()> {
    actix_rt::spawn(async move {
        let expression = "1/50   *   *     *       *  *  *";
        let schedule = Schedule::from_str(expression).unwrap();
        let offset = Some(FixedOffset::east(0)).unwrap();

        loop {
            let mut upcoming = schedule.upcoming(offset).take(1);
            actix_rt::time::sleep(Duration::from_millis(500)).await;
            let local = &Local::now();

            if let Some(datetime) = upcoming.next() {
                if datetime.timestamp() <= local.timestamp() {

                    let result = get_ips().await;
                    println!("{:?}",result);
                }
            }
        }
    });
    HttpServer::new(|| {
        App::new()
            .route("/hello", web::get().to(|| async { "Hello World!" }))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}
Вход в полноэкранный режим Выход из полноэкранного режима

Давайте попробуем понять, что нового здесь происходит

выражение cron : следуйте шаблону cron. Если вы хотите узнать об этом больше, то здесь.

//                  sec  min   hour   day of month   month   day of week   year
  let expression = "0   30   9,12,15     1,15       May-Aug  Mon,Wed,Fri  2018/2";
Вход в полноэкранный режим Выход из полноэкранного режима

Schedule::from_str : IT будет разбирать значение из строки.

FixedOffset : Фиксированное смещение используется для создания экземпляра даты. Положительные секунды означают Северное полушарие, а отрицательные — Западное полушарие.

schedule.upcoming(offset).take(1) : upcoming берет экземпляр смещения и возвращает итератор объекта DateTime, который соответствует расписанию.

  • take : возвращает первый элемент в итераторе.

thread::sleep : необходимо заснуть перед проверкой условий, потому что проверка условий в каждую миллисекунду не идеальна, так как в нашем случае используются секунды или больше. Если вам нужен контроль минутных миллисекунд над cron, вы можете попробовать и меньшее время.

Local::now() : Возвращает текущее время в зависимости от местного часового пояса.

if let Some(datetime) = upcoming.next() {if datetime.timestamp() <= local.timestamp() {} } : Если мы найдем объект datetime в итераторе и локальное время даты (текущее) >= времени итератора, то будет запущена функция.

4. Выполнение операций с БД с помощью cronjobs.

Это довольно похоже, как и два предыдущих. Я постараюсь дать вам представление и пример кода, чтобы вы могли понять сами.

Мы будем использовать clousure(move) над функцией для получения пула БД и логгера.

Пожалуйста, найдите код здесь, actix-question-bank-stackoverflow.

Особая благодарность cronjob. Он вдохновил меня на написание простого планировщика cron.

Не стесняйтесь задавать вопросы и делать pull request для изменений и предложений на GitHub.

Github — исходный код

Счастливого хакинга
Rustaceans!

Оцените статью
devanswers.ru
Добавить комментарий