Task scheduler for the Internet Computer

Overview

IC Cron

Makes your IC canister proactive

Abstract

Canisters are reactive by their nature - they only do something when they're asked by a client or another canister. But what if you need your canister to do something automatically after some time passes? For example, what if you want your canister to transfer some tokens on your behalf each month? Or maybe you want your canister to send you a "Good morning!" message through OpenChat each morning?

The only way to achieve such a behaviour before was to introduce an off-chain component, that will wait the time you need and then call canister's functions you want. This component could be either an edge device (such as user's smartphone) or some centralized cloud instance like AWS.

But not anymore. With ic-cron you can do all of this stuff completely on-chain for a reasonable price. No more centralized "clock-bots", no more complex Uniswap-like patterns when each user helps with recurrent task execution. Just schedule a task and your good to go.

And it is just a rust library.

Installation

# Cargo.toml

[dependencies]
ic-cron = "0.2.8"

Usage

{ ... }, Err(e) => trap(e), }; } ... // inside any #[update] function // enqueue a task cron_enqueue( // set a task kind so later you could decide how to handle it's execution TaskKind::SendGoodMorning as u8, // set a task payload - any CandidType is supported, so custom types would also work fine String::from("sweetie"), // set a scheduling interval (how often and how many times to execute) ic_cron::types::SchedulingInterval { 1_000_000_000 * 10, // each 10 seconds iterations: Iterations::Exact(20), // until executed 20 times }, ); ">
// somewhere in your canister's code

ic_cron::implement_cron!();

// this step is optional - you can use simple u8's to differ between task handlers
ic_cron::u8_enum! {
    pub enum TaskKind {
        SendGoodMorning,
        TransferTokens,
    }
}

// define a task handler function
// it will be automatically invoked each time a task is ready to be executed
fn _cron_task_handler(task: ScheduledTask) {
    match task.get_kind().try_into() {
        Ok(TaskKind::SendGoodMorning) => {
            let name = task.get_payload::<String>().unwrap();
      
            // will print "Good morning, sweetie!"      
            say(format!("Good morning, {}!", name));
        },
        Ok(TaskKind::TransferTokens) => {
            ...
        },
        Err(e) => trap(e),
    };
}

...

// inside any #[update] function
// enqueue a task
cron_enqueue(
    // set a task kind so later you could decide how to handle it's execution
    TaskKind::SendGoodMorning as u8,
    // set a task payload - any CandidType is supported, so custom types would also work fine
    String::from("sweetie"), 
    // set a scheduling interval (how often and how many times to execute)
    ic_cron::types::SchedulingInterval {
        1_000_000_000 * 10, // each 10 seconds
        iterations: Iterations::Exact(20), // until executed 20 times
    },
);

How many cycles does it consume?

I did not run any benchmarking at this moment, but it is pretty efficient. Simple math says it should add around $2/mo overhead considering your canister always having a scheduled task in queue. If the scheduling is eventual (sometimes you have a pending task, sometimes you don't) - it should consume even less.

Q: Does complexity of my tasks adds another overhead to cycles consumption?

A: No! You only pay for what you've coded. No additional cycles are wasted.

Q: What if I have multiple canisters each of which needs this behaviour?

A: In this case you can encapsulate ic-cron into a single separate cron-canister and ask it to schedule tasks for your other canisters.

How does it work?

It is pretty simple. It abuses the IC's messaging mechanics so your canister starts sending a wake-up message to itself. Once this message is received, it checks if there are scheduled tasks which could be executed at this exact moment. If there are some, it passes them to the _cron_task_handler() function one by one, and then sends the special message once again. If no more enqueued tasks left, it stops sending the message. Once a new task is enqueued, it starts to send the message again.

So, basically it uses a weird infinite loop to eventually wake the canister up to do some work.

Limitations

  1. Right now ic-cron doesn't support canister upgrades, so all your queued tasks will be lost. This is due to a limitation in ic-cdk, which doesn't support multiple stable variables at this moment. Once they do, I'll update this library, so it will handle canister upgrades gracefully. If you really want this functionality right now, you may try to serialize the state manually using get_cron_state() function.

  2. Since ic-cron can't pulse faster than the consensus ticks, it has an error of ~2s. So make sure you're not using a duration_nano interval less than 3s, otherwise it won't work as expected.

API

See the example project for better understanding.

implement_cron!()

This macro will implement all the functions you will use: get_cron_state(), cron_enqueue(), cron_dequeue() as well as a new #[update] endpoint for your canister - _cron_pulse(), on which your canister will send the wake-up message.

Basically this macros implements an inheritance pattern. Just like in a regular object-oriented programming language. Check the source code for further info.

cron_enqueue()

Schedules a new task. Returns task id, which then can be used in cron_dequeue() to deschedule the task.

Params:

  • kind: u8 - used to differentiate the way you want to process this task once it's executed
  • payload: CandidType - the data you want to provide with the task
  • scheduling_interval: SchedulingInterval - how often your task should be executed and how many times it should be rescheduled

Returns:

  • ic_cdk::export::candid::Result - Ok(task id) if everything is fine, and Err if there is a serialization issue with your payload

cron_dequeue()

Deschedules the task, removing it from the queue.

Params:

  • task_id: u64 - an id of the task you want to delete from the queue

Returns:

  • Option - Some(task), if the operation was a success; None, if there was no such task.

u8_enum!()

Helper macro which will automatically derive TryInto for your enum.

get_cron_state()

Returns an object which can be used to observe scheduler's state and modify it. Mostly intended for advanced users who want to extend ic-cron. See the source code for further info.

Candid

You don't need to modify your .did file for this library to work.

Contribution

You can reach me out here on github opening an issue, or you could start a thread on dfinity's developer forum.

You're also welcome to suggest new features and open PR's.

You might also like...
A rust library containing typings and utility functions dealing with the Public specification of the Internet Computer.

IC Types Contributing Please follow the guidelines in the CONTRIBUTING.md document. Goal This library contains typings and utility functions dealing w

Terabethia - A Bridge and Messaging Protocol between Ethereum and the Internet Computer.
Terabethia - A Bridge and Messaging Protocol between Ethereum and the Internet Computer.

Terabethia - A Bridge Between Ethereum & the Internet Computer Terabethia is a bridge between Ethereum & the Internet Computer that contracts in both

DIP721 - An Internet Computer Non-fungible Token Standard
DIP721 - An Internet Computer Non-fungible Token Standard

DIP721 - Introduction DIP721 is an ERC-721 style non-fungible token standard built mirroring its Ethereum counterpart and adapting it to the Internet

DIP20: A fungible token standard for the DFINITY Internet Computer.
DIP20: A fungible token standard for the DFINITY Internet Computer.

DIP20 - Introduction Token standards are essential for the Internet Computer ecosystem, especially for the decentralized finance ecosystem (DeFi) syst

A rust-based command line tool to serve as a gateway for a Internet Computer replica.

icx-proxy A command line tool to serve as a gateway for a Internet Computer replica. Contributing Please follow the guidelines in the CONTRIBUTING.md

A preview of the integration between Bitcoin and the Internet Computer.

Bitcoin Integration Developer Preview Overview The integration between the Internet Computer and Bitcoin will enable developers to build canisters tha

Rust library for build smart contracts on Internet Computer, by the Spinner.Cash team.

Spinner Rust library for building smart contracts on the Internet Computer. More specifically it is used by Spinner.Cash, a decentralized layer-2 prot

A demo of the Internet Computer's Bitcoin API

Bitcoin Integration Demo A demo of the bitcoin endpoints on the Internet Computer. This demo is already deployed to the IC, so you can already try it

Simple PoC to issue JSON Web Tokens (JWTs) with a canister on the Internet Computer.

JWT Issuer Proof of Concept Overview Simple PoC to issue JSON Web Tokens (JWTs) with a canister on the Internet Computer. It allows the issuance of tw

Rust flavor of the popular cron scheduler croner.

Croner Croner is a fully featured, lightweight, efficient Rust library for parsing and evaluating cron patterns. Designed with simplicity and performa

Async Rust cron scheduler running on Tokio.

Grizzly Cron Scheduler A simple and easy to use scheduler, built on top of Tokio, that allows you to schedule async tasks using cron expressions (with

🎭 A CLI task runner defined by a simple markdown file
🎭 A CLI task runner defined by a simple markdown file

mask is a CLI task runner which is defined by a simple markdown file. It searches for a maskfile.md in the current directory which it then parses for

Task runner and process manager for Rust
Task runner and process manager for Rust

Steward Task runner and process manager for Rust. If you're not happy managing your infrastructure with a pile of bash scripts, this crate might be he

delicate A lightweight and distributed task scheduling platform written in rust
delicate A lightweight and distributed task scheduling platform written in rust

A lightweight and distributed task scheduling platform written in rust.

Rust library to ease the task of creating daemons

Rust library to ease the task of creating daemons

Rust task runner and build tool.

cargo-make Rust task runner and build tool. Overview Installation Binary Release Usage Simple Example Tasks, Dependencies and Aliases Commands, Script

TimeKnight is a neat little TUI-based timer app I use in conjunction with a task tracker
TimeKnight is a neat little TUI-based timer app I use in conjunction with a task tracker

TimeKnight is a neat little TUI-based timer app I use in conjunction with a task tracker. It's kind of a secret sauce for productivity (particularly if you have ADHD or have a ridiculously overactive brain).

Task-based logging for rust
Task-based logging for rust

task_log task_log is a task-based logger. Installing Just add task_log = 0.1.4 to your Cargo.toml's dependency section. Example Let's get right to the

A terminal-based daily task management tool with minimal overhead
A terminal-based daily task management tool with minimal overhead

Arenta A terminal-based daily task management tool with minimal overhead. Demo Features Complete CRUD support of daily tasks with intuitive syntax Vis

Comments
  • IC-Cron Service

    IC-Cron Service

    Hey @seniorjoinu,

    have you considered deploying a service based on this to the IC where canisters can register themselves (against a few) to be notified?

    Would be cool to have economically self-sufficient service like this on the IC :)

    opened by domwoe 2
  • Unable to run yarn test

    Unable to run yarn test

    On ubuntu 20.04, dfx : 0.8.4

    yarn test yarn run v1.22.15 $ ts-mocha --paths --timeout 1000000 src/**/*.spec.ts

    Error: Cannot find module 'dfx-idl/ic-cron-example/ic-cron-example'


    yarn start seems to work in the prior step

    yarn start yarn run v1.22.15 $ dfx start --clean Starting webserver for /_/ binding to: 127.0.0.1:39575 .... Dec 06 20:21:06.604 WARN s:gj7o2-tv6sz-egnnq-zjllt-paj4g-zlonj-jr7u5-bt632-5ymwn-g46ly-sae/n:zxe2u-fcrwj-jrji2-laj6m-xskov-ti2t4-nxped-teak3-qj4wg-jftrt-6qe/ic_state_layout/utils StateManager runs on a filesystem not supporting reflinks (attempted to reflink /home/xyz/src/ic/ic-cron/example/e2e-test/.dfx/state/replicated_state/node-100/state/tip/system_metadata.pbuf => /home/xyz/src/ic/ic-cron/example/e2e-test/.dfx/state/replicated_state/node-100/state/fs_tmp/scratchpad_0000000000000064/system_metadata.pbuf), running big canisters can be very slow

    opened by icdev2dev 1
Releases(0.5.1)
Owner
Alexander Vtyurin
https://t.me/joinu14
Alexander Vtyurin
Task runner and process manager for Rust

Steward Task runner and process manager for Rust. If you're not happy managing your infrastructure with a pile of bash scripts, this crate might be he

Alex Fedoseev 24 Dec 26, 2022
delicate A lightweight and distributed task scheduling platform written in rust

A lightweight and distributed task scheduling platform written in rust.

BinCheng 529 Jan 9, 2023
Rust library to ease the task of creating daemons

Rust library to ease the task of creating daemons

Matheus Xavier 38 Nov 25, 2022
Cronos - a decentralized task scheduler for Solana

Cronos Cronos is a decentralized task scheduler for Solana. Packages Package Description Version Docs cronos-bot Cronos bot to execute tasks GitBook c

null 174 Dec 26, 2022
Dank - The Internet Computer Decentralized Bank - A collection of Open Internet Services - Including the Cycles Token (XTC)

Dank - The Internet Computer Decentralized Bank Dank is a collection of Open Internet Services for users and developers on the Internet Computer. In t

Psychedelic 56 Nov 12, 2022
Open Internet Service to store transaction history for NFTs/Tokens on the Internet Computer

CAP - Certified Asset Provenance Transaction history & asset provenance for NFT’s & Tokens on the Internet Computer CAP is an open internet service pr

Psychedelic 42 Nov 10, 2022
Cover is an open internet service for canister code verification on the Internet Computer

Cover Cover (short for Code Verification) is an open internet service that helps verify the code of canisters on the Internet Computer. Visit our webs

Psychedelic 14 Oct 31, 2022
Easy c̵̰͠r̵̛̠ö̴̪s̶̩̒s̵̭̀-t̶̲͝h̶̯̚r̵̺͐e̷̖̽ḁ̴̍d̶̖̔ ȓ̵͙ė̶͎ḟ̴͙e̸̖͛r̶̖͗ë̶̱́ṉ̵̒ĉ̷̥e̷͚̍ s̷̹͌h̷̲̉a̵̭͋r̷̫̊ḭ̵̊n̷̬͂g̵̦̃ f̶̻̊ơ̵̜ṟ̸̈́ R̵̞̋ù̵̺s̷̖̅ţ̸͗!̸̼͋

Rust S̵̓i̸̓n̵̉ I̴n̴f̶e̸r̵n̷a̴l mutability! Howdy, friendly Rust developer! Ever had a value get m̵̯̅ð̶͊v̴̮̾ê̴̼͘d away right under your nose just when

null 294 Dec 23, 2022
Source project for the Internet Computer software

The Internet Computer is the world’s first blockchain that runs at web speed and can increase its capacity without bound. Like the Internet (which is composed of many machines adhering to TCP/IP protocol) and blockchain protocols (such as Bitcoin and Ethereum).

DFINITY 1.2k Jan 1, 2023
Agent library for Internet Computer, in Dart

An agent library built for Internet Computer, a plugin package for dart and flutter apps. Developers can build ones to interact with Dfinity's blockchain directly.

null 87 Dec 31, 2022