IC Cron - let's schedule some tasks bois

Oh, and if I read

        #[allow(unused_must_use)]
        fn _call_cron_pulse() {
            if get_cron_state().is_running {
                ic_cdk::block_on(async {
                    ic_cdk::call::<(), ()>(ic_cdk::id(), "_cron_pulse", ())
                        .await
                        .unwrap();
                });
            };
        }

        #[ic_cdk_macros::update]
        fn _cron_pulse() {
            for task in get_cron_state().iterate(ic_cdk::api::time()) {
                _cron_task_handler(task);
            }

            _call_cron_pulse();
        }

correctly then you ran into the same mistake that others ran before: Your pulse function calls itself recursively. This means you are accumulating call contexts without bound, which will cause issues eventually.

The better way to do this (in pseudo-code) is roughly

            ic_cdk::block_on(async {
                while get_cron_state().is_running {
                    ic_cdk::call::<(), ()>(ic_cdk::id(), "_cron_ping", ())
                        .await
                        .unwrap();
                    for task in get_cron_state().iterate(ic_cdk::api::time()) {
                        _cron_task_handler(task);
                   }
               }}

In other words: don’t use recursion, use loops, as otherwise the stack grows.

3 Likes