#cron #internet-computer #ic #task-scheduling #dfinity

ic-cron

互联网计算机的任务调度 Rust 库

22 个版本

0.7.1 2022年11月11日
0.7.0 2022年3月28日
0.6.1 2022年3月4日
0.5.1 2022年1月31日
0.1.5 2021年8月8日

#27#task-scheduling

Download history 64/week @ 2024-07-30

每月 64 次下载
currency-token-client 中使用

MIT 许可证

28KB
580

IC Cron

互联网计算机的任务调度 Rust 库

动机

IC 提供了内置的 "心跳" 功能,这实际上是一个每次达成共识时都会执行的特殊函数。但这对于全面的任务调度还不够,你仍然需要自己实现调度逻辑。这个 Rust 库正是这样做的——为你提供简单的 API,用于复杂的后台调度场景,以在任意特定时间执行你的代码,次数不限。

安装

确保您正在使用 dfx 0.8.4 或更高版本。

# Cargo.toml

[dependencies]
ic-cron = "0.7"

用法

// somewhere in your canister's code
ic_cron::implement_cron!();

#[derive(CandidType, Deserialize)]
enum TaskKind {
    SendGoodMorning(String),
    DoSomethingElse,
}

// enqueue a task
#[ic_cdk_macros::update]
pub fn enqueue_task_1() {
    cron_enqueue(
        // set a task payload - any CandidType is supported
        TaskKind::SendGoodMorning(String::from("sweetie")),
        // set a scheduling interval (how often and how many times to execute)
        ic_cron::types::SchedulingOptions {
            1_000_000_000 * 60 * 5, // after waiting for 5 minutes delay once
            1_000_000_000 * 10, // each 10 seconds
            iterations: Iterations::Exact(20), // until executed 20 times
        },
    );
}

// enqueue another task
#[ic_cdk_macros::update]
pub fn enqueue_task_2() {
    cron_enqueue(
        TaskKind::DoSomethingElse,
        ic_cron::types::SchedulingOptions {
            0, // start immediately
            1_000_000_000 * 60 * 5, // each 5 minutes
            iterations: Iterations::Infinite, // repeat infinitely
        },
    );
}

// in a canister heartbeat function get all tasks ready for execution at this exact moment and use it
#[ic_cdk_macros::heartbeat]
fn heartbeat() {
    // cron_ready_tasks will only return tasks which should be executed right now
    for task in cron_ready_tasks() {
        let kind = task.get_payload::<TaskKind>().expect("Serialization error");
      
        match kind {
            TaskKind::SendGoodMorning(name) => {
                // will print "Good morning, sweetie!"      
                println!("Good morning, {}!", name);
            },
            TaskKind::DoSomethingElse => {
                ...
            },
        };   
    }
}

它消耗多少周期?

因为这个库只是一个花哨的任务队列,所以在周期方面没有显著的开销。

它是如何工作的?

这个库使用内置的 canister 心跳功能。每次将任务入队时,它都会被添加到任务队列中。任务可以以不同的方式进行调度——它们可以执行特定次数或无限次。这与你在 JavaScript 中使用 setTimeout()setInterval() 的方式非常相似,但更灵活。每次调用 canister_heartbeat 函数时,您都必须调用 cron_ready_tasks() 函数,该函数高效地遍历任务队列,弹出计划执行时间戳小于等于当前时间戳的任务。重新安排的任务将它们的下一次执行时间戳与其上一次计划执行时间戳相关联——这样调度器可以补偿由不稳定共识间隔引起的错误。

限制

由于 ic-cron 的心跳频率不能超过共识周期,因此它有一个大约 2 秒的误差。

教程

API

请参阅 示例项目 以获得更好的理解。

implement_cron!()

本宏将实现您将使用的所有功能:get_cron_state()cron_enqueue()cron_dequeue()cron_ready_tasks()

基本上,这个宏实现了继承模式,就像在常规面向对象编程语言中一样。查看源代码获取更多信息。

cron_enqueue()

安排新的任务。返回任务ID,然后可以在cron_dequeue()中使用来取消安排任务。

参数

  • payload: CandidType - 您想要与任务一起提供的数据
  • scheduling_interval: SchedulingInterval - 您的任务应执行的频率和重新安排的次数

返回值

  • ic_cdk::export::candid::Result<u64> - 如果一切顺利,返回Ok(任务ID),如果您的payload存在序列化问题,则返回Err

cron_dequeue()

取消安排任务,从队列中删除它。

参数

  • task_id: u64 - 您想要从队列中删除的任务ID

返回值

  • Option<ScheduledTask> - 如果操作成功,返回Some(任务);如果不存在此类任务,则返回None

cron_ready_tasks()

返回一个可以立即执行的任务vec。

返回值

  • Vec<ScheduledTask> - 待处理任务的vec

get_cron_state()

返回一个静态可变引用到对象,该对象可用于观察调度程序的状态并修改它。主要用于想要扩展ic-cron的高级用户。查看源代码获取更多信息。

_take_cron_state()

返回(移动)cron状态。用于在不进行状态克隆的情况下升级canister。确保在调用此函数后不要使用get_cron_state()之前调用_put_cron_state()

_put_cron_state()

设置任务调度器的全局状态,因此可以通过get_cron_state()函数访问此新状态。

参数

  • Option<TaskScheduler> - 可以从get_cron_state()函数获取的状态对象

这两个函数可以用于在canister升级之间持久化安排的任务

#[ic_cdk_macros::pre_upgrade]
fn pre_upgrade_hook() {
    let cron_state = _take_cron_state();

    stable_save((cron_state,)).expect("Unable to save the state to stable memory");
}

#[ic_cdk_macros::post_upgrade]
fn post_upgrade_hook() {
    let (cron_state,): (Option<TaskScheduler>,) =
          stable_restore().expect("Unable to restore the state from stable memory");

    _put_cron_state(cron_state);
}

Candid

您无需修改您的.did文件即可使此库工作。

贡献

您可以在GitHub上通过创建问题来联系我,或者您也可以在Dfinity开发者论坛上发帖。

您也可以提出新功能和打开PR。

依赖项

~4–13MB
~131K SLoC