Skip to content

Commit 00d8eea

Browse files
bkchrgithub-actions[bot]gui1117rockbmb
authored
pallet-scheduler: Put back postponed tasks into the agenda (#7790)
Right now `pallet-scheduler` is not putting back postponed tasks into the agenda when the early weight check is failing. This pull request ensures that these tasks are put back into the agenda and are not just "lost". --------- Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Guillaume Thiolliere <[email protected]> Co-authored-by: Alexandre R. Baldé <[email protected]>
1 parent 945e5fe commit 00d8eea

File tree

4 files changed

+63
-15
lines changed

4 files changed

+63
-15
lines changed

prdoc/pr_7790.prdoc

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
title: 'pallet-scheduler: Put back postponed tasks into the agenda'
2+
doc:
3+
- audience: Runtime Dev
4+
description: "Right now `pallet-scheduler` is not putting back postponed tasks into\
5+
\ the agenda when the early weight check is failing. This pull request ensures\
6+
\ that these tasks are put back into the agenda and are not just \"lost\".\r\n"
7+
crates:
8+
- name: pallet-scheduler
9+
bump: patch

substrate/frame/scheduler/src/lib.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ pub mod pallet {
323323
type BlockNumberProvider: BlockNumberProvider;
324324
}
325325

326+
/// Block number at which the agenda began incomplete execution.
326327
#[pallet::storage]
327328
pub type IncompleteSince<T: Config> = StorageValue<_, BlockNumberFor<T>>;
328329

@@ -386,6 +387,8 @@ pub mod pallet {
386387
RetryFailed { task: TaskAddress<BlockNumberFor<T>>, id: Option<TaskName> },
387388
/// The given task can never be executed since it is overweight.
388389
PermanentlyOverweight { task: TaskAddress<BlockNumberFor<T>>, id: Option<TaskName> },
390+
/// Agenda is incomplete from `when`.
391+
AgendaIncomplete { when: BlockNumberFor<T> },
389392
}
390393

391394
#[pallet::error]
@@ -1202,6 +1205,7 @@ impl<T: Config> Pallet<T> {
12021205
}
12031206
incomplete_since = incomplete_since.min(when);
12041207
if incomplete_since <= now {
1208+
Self::deposit_event(Event::AgendaIncomplete { when: incomplete_since });
12051209
IncompleteSince::<T>::put(incomplete_since);
12061210
}
12071211
}
@@ -1235,17 +1239,15 @@ impl<T: Config> Pallet<T> {
12351239
let mut dropped = 0;
12361240

12371241
for (agenda_index, _) in ordered.into_iter().take(max as usize) {
1238-
let task = match agenda[agenda_index as usize].take() {
1239-
None => continue,
1240-
Some(t) => t,
1241-
};
1242+
let Some(task) = agenda[agenda_index as usize].take() else { continue };
12421243
let base_weight = T::WeightInfo::service_task(
12431244
task.call.lookup_len().map(|x| x as usize),
12441245
task.maybe_id.is_some(),
12451246
task.maybe_periodic.is_some(),
12461247
);
12471248
if !weight.can_consume(base_weight) {
12481249
postponed += 1;
1250+
agenda[agenda_index as usize] = Some(task);
12491251
break
12501252
}
12511253
let result = Self::service_task(weight, now, when, agenda_index, *executed == 0, task);

substrate/frame/scheduler/src/mock.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ impl WeightInfo for TestWeightInfo {
212212
}
213213
}
214214
parameter_types! {
215-
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
215+
pub storage MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
216216
BlockWeights::get().max_block;
217217
}
218218

substrate/frame/scheduler/src/tests.rs

+47-10
Original file line numberDiff line numberDiff line change
@@ -1264,8 +1264,8 @@ fn cancel_named_periodic_scheduling_works() {
12641264

12651265
#[test]
12661266
fn scheduler_respects_weight_limits() {
1267-
let max_weight: Weight = <Test as Config>::MaximumWeight::get();
12681267
new_test_ext().execute_with(|| {
1268+
let max_weight: Weight = <Test as Config>::MaximumWeight::get();
12691269
let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 * 2 });
12701270
assert_ok!(Scheduler::do_schedule(
12711271
DispatchTime::At(4),
@@ -1292,8 +1292,8 @@ fn scheduler_respects_weight_limits() {
12921292

12931293
#[test]
12941294
fn retry_respects_weight_limits() {
1295-
let max_weight: Weight = <Test as Config>::MaximumWeight::get();
12961295
new_test_ext().execute_with(|| {
1296+
let max_weight: Weight = <Test as Config>::MaximumWeight::get();
12971297
// schedule 42
12981298
let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 * 2 });
12991299
assert_ok!(Scheduler::do_schedule(
@@ -1344,8 +1344,8 @@ fn retry_respects_weight_limits() {
13441344

13451345
#[test]
13461346
fn try_schedule_retry_respects_weight_limits() {
1347-
let max_weight: Weight = <Test as Config>::MaximumWeight::get();
13481347
new_test_ext().execute_with(|| {
1348+
let max_weight: Weight = <Test as Config>::MaximumWeight::get();
13491349
let service_agendas_weight = <Test as Config>::WeightInfo::service_agendas_base();
13501350
let service_agenda_weight = <Test as Config>::WeightInfo::service_agenda_base(
13511351
<Test as Config>::MaxScheduledPerBlock::get(),
@@ -1404,8 +1404,8 @@ fn try_schedule_retry_respects_weight_limits() {
14041404
/// Permanently overweight calls are not deleted but also not executed.
14051405
#[test]
14061406
fn scheduler_does_not_delete_permanently_overweight_call() {
1407-
let max_weight: Weight = <Test as Config>::MaximumWeight::get();
14081407
new_test_ext().execute_with(|| {
1408+
let max_weight: Weight = <Test as Config>::MaximumWeight::get();
14091409
let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight });
14101410
assert_ok!(Scheduler::do_schedule(
14111411
DispatchTime::At(4),
@@ -1430,10 +1430,10 @@ fn scheduler_does_not_delete_permanently_overweight_call() {
14301430

14311431
#[test]
14321432
fn scheduler_handles_periodic_failure() {
1433-
let max_weight: Weight = <Test as Config>::MaximumWeight::get();
1434-
let max_per_block = <Test as Config>::MaxScheduledPerBlock::get();
1435-
14361433
new_test_ext().execute_with(|| {
1434+
let max_weight: Weight = <Test as Config>::MaximumWeight::get();
1435+
let max_per_block = <Test as Config>::MaxScheduledPerBlock::get();
1436+
14371437
let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: (max_weight / 3) * 2 });
14381438
let bound = Preimage::bound(call).unwrap();
14391439

@@ -1472,9 +1472,9 @@ fn scheduler_handles_periodic_failure() {
14721472

14731473
#[test]
14741474
fn scheduler_handles_periodic_unavailable_preimage() {
1475-
let max_weight: Weight = <Test as Config>::MaximumWeight::get();
1476-
14771475
new_test_ext().execute_with(|| {
1476+
let max_weight: Weight = <Test as Config>::MaximumWeight::get();
1477+
14781478
let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: (max_weight / 3) * 2 });
14791479
let hash = <Test as frame_system::Config>::Hashing::hash_of(&call);
14801480
let len = call.using_encoded(|x| x.len()) as u32;
@@ -1518,8 +1518,8 @@ fn scheduler_handles_periodic_unavailable_preimage() {
15181518

15191519
#[test]
15201520
fn scheduler_respects_priority_ordering() {
1521-
let max_weight: Weight = <Test as Config>::MaximumWeight::get();
15221521
new_test_ext().execute_with(|| {
1522+
let max_weight: Weight = <Test as Config>::MaximumWeight::get();
15231523
let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 });
15241524
assert_ok!(Scheduler::do_schedule(
15251525
DispatchTime::At(4),
@@ -3039,3 +3039,40 @@ fn unavailable_call_is_detected() {
30393039
assert!(!Preimage::is_requested(&hash));
30403040
});
30413041
}
3042+
3043+
#[test]
3044+
fn postponed_task_is_still_available() {
3045+
new_test_ext().execute_with(|| {
3046+
let service_agendas_weight = <Test as Config>::WeightInfo::service_agendas_base();
3047+
let service_agenda_weight = <Test as Config>::WeightInfo::service_agenda_base(
3048+
<Test as Config>::MaxScheduledPerBlock::get(),
3049+
);
3050+
3051+
assert_ok!(Scheduler::schedule(
3052+
RuntimeOrigin::root(),
3053+
4,
3054+
None,
3055+
128,
3056+
Box::new(RuntimeCall::from(frame_system::Call::remark {
3057+
remark: vec![0u8; 3 * 1024 * 1024],
3058+
}))
3059+
));
3060+
System::run_to_block::<AllPalletsWithSystem>(3);
3061+
// Scheduled calls are in the agenda.
3062+
assert_eq!(Agenda::<Test>::get(4).len(), 1);
3063+
3064+
let old_weight = MaximumSchedulerWeight::get();
3065+
MaximumSchedulerWeight::set(&service_agenda_weight.saturating_add(service_agendas_weight));
3066+
3067+
System::run_to_block::<AllPalletsWithSystem>(4);
3068+
3069+
// The task should still be there.
3070+
assert_eq!(Agenda::<Test>::get(4).iter().filter(|a| a.is_some()).count(), 1);
3071+
System::assert_last_event(crate::Event::AgendaIncomplete { when: 4 }.into());
3072+
3073+
// Now it should get executed
3074+
MaximumSchedulerWeight::set(&old_weight);
3075+
System::run_to_block::<AllPalletsWithSystem>(5);
3076+
assert!(Agenda::<Test>::get(4).is_empty());
3077+
});
3078+
}

0 commit comments

Comments
 (0)