Attribute Macro frame_support_procedural::tasks_experimental

source ·
#[tasks_experimental]
Expand description

Allows you to define some service work that can be recognized by a script or an off-chain worker.

Such a script can then create and submit all such work items at any given time.

These work items are defined as instances of the Task trait (found at frame_support::traits::Task). pallet:tasks_experimental when attached to an impl block inside a pallet, will generate an enum Task<T> whose variants are mapped to functions inside this impl block.

Each such function must have the following set of attributes:

All of such Tasks are then aggregated into a RuntimeTask by construct_runtime.

Finally, the RuntimeTask can then used by a script or off-chain worker to create and submit such tasks via an extrinsic defined in frame_system called do_task.

When submitted as unsigned transactions (for example via an off-chain workder), note that the tasks will be executed in a random order.

§Example

#[pallet::tasks_experimental]
impl<T: Config> Pallet<T> {
	/// Add a pair of numbers into the totals and remove them.
	#[pallet::task_list(Numbers::<T>::iter_keys())]
	#[pallet::task_condition(|i| Numbers::<T>::contains_key(i))]
	#[pallet::task_weight(0.into())]
	#[pallet::task_index(0)]
	pub fn add_number_into_total(i: u32) -> DispatchResult {
		let v = Numbers::<T>::take(i).ok_or(Error::<T>::NotFound)?;
		Total::<T>::mutate(|(total_keys, total_values)| {
			*total_keys += i;
			*total_values += v;
		});
		Ok(())
	}
}

Now, this can be executed as follows:

#[test]
fn tasks_work() {
	super::new_test_ext().execute_with(|| {
		Numbers::<Runtime>::insert(0, 1);

		let task = RuntimeTask::System(super::frame_system::Task::<Runtime>::AddNumberIntoTotal {
			i: 0u32,
		});

		assert_ok!(System::do_task(RuntimeOrigin::signed(1), task.clone(),));
		assert_eq!(Numbers::<Runtime>::get(0), None);
		assert_eq!(Total::<Runtime>::get(), (0, 1));
	});
}