Skip to content

Commit cce6561

Browse files
fix: reply after the timer body (#679)
* Move reply after task await * Add test and fix * ensure test fails on main * improve the test --------- Co-authored-by: Linwei Shang <[email protected]>
1 parent 07c3acb commit cce6561

File tree

3 files changed

+51
-12
lines changed

3 files changed

+51
-12
lines changed

e2e-tests/src/bin/timers.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ fn start_repeating() {
8181
REPEATING.with(|repeating| repeating.set(id));
8282
}
8383

84+
#[update]
85+
fn start_repeating_async() {
86+
let id = set_timer_interval(Duration::from_secs(1), async || {
87+
Call::bounded_wait(canister_self(), "add_event_method")
88+
.with_arg("repeat")
89+
.await
90+
.unwrap();
91+
});
92+
REPEATING.with(|repeating| repeating.set(id));
93+
}
94+
8495
#[update]
8596
fn set_self_cancelling_periodic_timer() {
8697
let id = set_timer_interval(Duration::from_secs(0), async || {

e2e-tests/tests/timers.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ use std::time::Duration;
44
mod test_utilities;
55
use test_utilities::{cargo_build_canister, pic_base, update};
66

7+
/// Advance the time by a given number of seconds.
8+
/// "tick" the IC every second so that it progress and produce a block so that timers get triggered.
9+
fn advance_seconds(pic: &PocketIc, seconds: u32) {
10+
for _ in 0..seconds {
11+
pic.advance_time(Duration::from_secs(1));
12+
pic.tick();
13+
}
14+
}
15+
716
#[test]
817
fn test_timers() {
918
let wasm = cargo_build_canister("timers");
@@ -86,13 +95,6 @@ fn test_scheduling_many_timers() {
8695
assert_eq!(timers_to_schedule, executed_timers);
8796
}
8897

89-
fn advance_seconds(pic: &PocketIc, seconds: u32) {
90-
for _ in 0..seconds {
91-
pic.advance_time(Duration::from_secs(1));
92-
pic.tick();
93-
}
94-
}
95-
9698
#[test]
9799
fn test_set_global_timers() {
98100
let wasm = cargo_build_canister("timers");
@@ -153,3 +155,25 @@ fn test_async_timers() {
153155
3
154156
);
155157
}
158+
159+
#[test]
160+
fn test_periodic_timers_repeat_when_task_make_calls() {
161+
let wasm = cargo_build_canister("timers");
162+
let pic = pic_base().build();
163+
164+
let canister_id = pic.create_canister();
165+
pic.add_cycles(canister_id, 2_000_000_000_000);
166+
pic.install_canister(canister_id, wasm, vec![], None);
167+
168+
update::<(), ()>(&pic, canister_id, "start_repeating_async", ()).unwrap();
169+
// start_repeating_async sets a repeating timer with a 1s interval
170+
// advance time by 3 seconds should trigger 3 repeats
171+
advance_seconds(&pic, 3);
172+
update::<(), ()>(&pic, canister_id, "stop_repeating", ()).unwrap();
173+
174+
let (events,): (Vec<String>,) = query_candid(&pic, canister_id, "get_events", ()).unwrap();
175+
assert_eq!(
176+
events[..],
177+
["method repeat", "method repeat", "method repeat"]
178+
);
179+
}

ic-cdk-timers/src/lib.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -255,9 +255,9 @@ unsafe extern "C" fn timer_scope_callback(env: usize) {
255255
return;
256256
}
257257
x => {
258-
let reject_data_size = ic0::msg_arg_data_size();
258+
let reject_data_size = ic0::msg_reject_msg_size();
259259
let mut reject_data = Vec::with_capacity(reject_data_size);
260-
ic0::msg_arg_data_copy_uninit(
260+
ic0::msg_reject_msg_copy_uninit(
261261
&mut reject_data.spare_capacity_mut()[..reject_data_size],
262262
0,
263263
);
@@ -475,7 +475,10 @@ extern "C" fn timer_executor() {
475475
if let Some(task) = task {
476476
match task {
477477
Task::Once(fut) => {
478-
ic_cdk_executor::spawn_protected(fut);
478+
ic_cdk_executor::spawn_protected(async {
479+
fut.await;
480+
ic0::msg_reply();
481+
});
479482
TASKS.with_borrow_mut(|tasks| tasks.remove(task_id));
480483
}
481484
Task::Repeated { func, interval } => {
@@ -496,11 +499,12 @@ extern "C" fn timer_executor() {
496499

497500
let mut guard = RepeatGuard(Some(func), task_id, interval);
498501
guard.0.as_mut().unwrap().call_mut().await;
502+
ic0::msg_reply();
499503
});
500504
}
501505
}
506+
} else {
507+
ic0::msg_reply();
502508
}
503-
ic0::msg_reply_data_append(&[]);
504-
ic0::msg_reply();
505509
});
506510
}

0 commit comments

Comments
 (0)