Skip to content

Commit 0faf927

Browse files
feat: remove ic-cdk dependency from ic-cdk-timers (#641)
1 parent f39b5a6 commit 0faf927

File tree

8 files changed

+375
-149
lines changed

8 files changed

+375
-149
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ candid = "0.10.18" # sync with the doc comment in ic-cdk/README.md
4242
candid_parser = "0.2.1"
4343
futures = "0.3"
4444
hex = "0.4"
45+
ic_principal = "0.1"
4546
quote = "1"
4647
serde = "1"
4748
serde_bytes = "0.11"

e2e-tests/src/bin/timers.rs

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use ic_cdk::{query, update};
1+
use futures::{stream::FuturesUnordered, StreamExt};
2+
use ic_cdk::{api::canister_self, call::Call, futures::spawn, query, update};
23
use ic_cdk_timers::{clear_timer, set_timer, set_timer_interval, TimerId};
34
use std::{
45
cell::{Cell, RefCell},
@@ -7,15 +8,15 @@ use std::{
78
};
89

910
thread_local! {
10-
static EVENTS: RefCell<Vec<&'static str>> = RefCell::default();
11+
static EVENTS: RefCell<Vec<String>> = RefCell::default();
1112
static LONG: Cell<TimerId> = Cell::default();
1213
static REPEATING: Cell<TimerId> = Cell::default();
1314
}
1415

1516
static EXECUTED_TIMERS: AtomicU32 = AtomicU32::new(0);
1617

1718
#[query]
18-
fn get_events() -> Vec<&'static str> {
19+
fn get_events() -> Vec<String> {
1920
EVENTS.with(|events| events.borrow().clone())
2021
}
2122

@@ -94,13 +95,47 @@ fn stop_repeating() {
9495
REPEATING.with(|repeating| clear_timer(repeating.get()));
9596
}
9697

97-
fn add_event(event: &'static str) {
98-
EVENTS.with(|events| events.borrow_mut().push(event));
98+
fn add_event(event: &str) {
99+
EVENTS.with(|events| events.borrow_mut().push(event.to_string()));
99100
}
100101

101102
#[update]
102103
fn global_timer_set(timestamp: u64) -> u64 {
103104
ic_cdk::api::global_timer_set(timestamp)
104105
}
105106

107+
#[update]
108+
fn add_event_method(name: &str) {
109+
add_event(&format!("method {name}"));
110+
}
111+
112+
#[update]
113+
fn async_await() {
114+
set_timer(Duration::from_secs(1), async {
115+
add_event("1");
116+
Call::bounded_wait(canister_self(), "add_event_method")
117+
.with_arg("outer")
118+
.await
119+
.unwrap();
120+
add_event("2");
121+
spawn(async {
122+
Call::bounded_wait(canister_self(), "add_event_method")
123+
.with_arg("spawned")
124+
.await
125+
.unwrap();
126+
});
127+
let futs = FuturesUnordered::new();
128+
for _ in 0..3 {
129+
futs.push(async move {
130+
Call::bounded_wait(canister_self(), "add_event_method")
131+
.with_arg("concurrent")
132+
.await
133+
.unwrap();
134+
});
135+
}
136+
futs.collect::<()>().await;
137+
});
138+
add_event("0")
139+
}
140+
106141
fn main() {}

e2e-tests/tests/timers.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ fn test_timers() {
1919
advance_seconds(&pic, 5);
2020
update::<_, ()>(&pic, canister_id, "cancel_long", ()).expect("Failed to call cancel_long");
2121
advance_seconds(&pic, 5);
22-
2322
update::<_, ()>(&pic, canister_id, "start_repeating", ())
2423
.expect("Failed to call start_repeating");
2524
advance_seconds(&pic, 3);
@@ -122,3 +121,35 @@ fn test_set_global_timers() {
122121
update::<(u64,), (u64,)>(&pic, canister_id, "global_timer_set", (0,)).unwrap();
123122
assert!(previous.abs_diff(t2) < 2); // time error no more than 1 nanosecond
124123
}
124+
125+
#[test]
126+
fn test_async_timers() {
127+
let wasm = cargo_build_canister("timers");
128+
let pic = pic_base().build();
129+
130+
let canister_id = pic.create_canister();
131+
pic.add_cycles(canister_id, 2_000_000_000_000);
132+
pic.install_canister(canister_id, wasm, vec![], None);
133+
134+
update::<(), ()>(&pic, canister_id, "async_await", ()).unwrap();
135+
advance_seconds(&pic, 5);
136+
137+
let (events,): (Vec<String>,) =
138+
query_candid(&pic, canister_id, "get_events", ()).expect("Failed to call get_events");
139+
assert_eq!(events.len(), 8);
140+
assert_eq!(events[..4], ["0", "1", "method outer", "2",]);
141+
assert_eq!(
142+
events[4..]
143+
.iter()
144+
.filter(|e| *e == "method spawned")
145+
.count(),
146+
1
147+
);
148+
assert_eq!(
149+
events[4..]
150+
.iter()
151+
.filter(|e| *e == "method concurrent")
152+
.count(),
153+
3
154+
);
155+
}

ic-cdk-timers/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [unreleased]
88

9-
- Timer bodies have been changed from `FnOnce`/`FnMut` to `Future`/`AsyncFnMut`, so `spawn` is no longer required to enter an async context from a timer. For `set_timer`, `|| {}` should be changed to `async {}`, and for `set_timer_interval`, `|| {}` should be changed to `async || {}`.
9+
- `ic-cdk-timers` no longer has a dependency on `ic-cdk` and no longer needs to be upgraded when `ic-cdk` is upgraded.
10+
- Breaking: Timer bodies have been changed from `FnOnce`/`FnMut` to `Future`/`AsyncFnMut`, so `spawn` is no longer required to enter an async context from a timer. For `set_timer`, `|| {}` should be changed to `async {}`, and for `set_timer_interval`, `|| {}` should be changed to `async || {}`.
11+
- If you have any immediate `spawn` calls, you can remove them and run the async code directly. (You do not have to.)
1012

1113
## [0.12.2] - 2025-06-25
1214

ic-cdk-timers/Cargo.toml

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,17 @@ description = "Timers library for the Rust CDK."
1010
homepage = "https://docs.rs/ic-cdk"
1111
documentation = "https://docs.rs/ic-cdk-timers"
1212
readme = "README.md"
13-
categories = [
14-
"api-bindings",
15-
"data-structures",
16-
"no-std",
17-
"development-tools::ffi",
18-
]
13+
categories = ["api-bindings", "data-structures", "no-std", "development-tools::ffi"]
1914
keywords = ["internet-computer", "dfinity", "canister", "cdk"]
2015
include = ["src", "Cargo.toml", "LICENSE", "README.md"]
2116

2217
[dependencies]
23-
candid.workspace = true
2418
ic0.workspace = true
25-
ic-cdk.workspace = true
26-
serde.workspace = true
27-
serde_bytes.workspace = true
19+
ic-cdk-executor.workspace = true
2820
slotmap.workspace = true
29-
futures.workspace = true
21+
22+
[dev-dependencies]
23+
ic-cdk.workspace = true
3024

3125
[package.metadata.docs.rs]
3226
default-target = "wasm32-unknown-unknown"

0 commit comments

Comments
 (0)