gear
gear copied to clipboard
Add ability to send scheduled messages
Problem to Solve
Sometimes we need to send the message after some delay instead of doing it immediately. It might be useful for time scheduled routines, e.g. in DAO, auctions, lotteries.
Possible Solution
Introduce new functions in gstd::msg
(all names, parameters, and return types are to be discussed!):
/// `msg` module
/// Add deferred message to the shedule.
fn defer(dest, payload, delay, value) -> Result<MessageId, ...>;
// fn defer_with_gas(...)
// async fn defer_for_reply(...)
/// Allow early sending.
fn allow_shoving(msg_id) -> bool;
/// Cancel sending deferred message.
fn cancel_deferred(msg_id) -> Result<(), ...>;
/// Send deferred message immediately.
fn shove(msg_id) -> Result<(), ...>;
// fn shove_for_reply(...)
Also need to add correspondent functionality to Gear core.
Notes
Using example (DAO):
let msg_id = msg::defer(
exec::program_id(),
DaoAction::ProcessProposal(self.proposal_id)),
exec::blick_timestamp() + self.voting_period,
0,
)
.expect("Error while deferring message");
msg::allow_shoving(msg_id);
let reply: DaoEvent =
exec::shove_as(msg_id).expect("Error while shoving deferred message");
exec::cancel_deferred(msg_id).expect("Error while cancelling deferred message");
let reply: DaoEvent = msg::defer_for_reply_as(
exec::program_id(),
DaoAction::ProcessProposal(self.proposal_id),
exec::block_timestamp() + self.voting_period,
0,
)
.expect("Error while deferring message")
.await
.expect("Error while processing result");
Defer is an ambiguous name because it is used in several programming languages with a different purpose https://www.educative.io/answers/what-is-the-defer-keyword-in-golang, https://www.hackingwithswift.com/new-syntax-swift-2-defer maybe we can use the word schedule
.
allow_shoving
can be replaced with allow_forced_execution
or allow_forced_firing
. Or early execution or something like this. We need to think about the advisability of this method, because it is far from being everywhere at all. We can just execute something and cancel job by messageId
Maybe we should consider argument like is_repeating_task: bool
or separate function with the same purpose.
I agree with @puzzle-rusher, schedule
is also more appropriate than defer
because defer
is something planned for an indefinite time, but schedule
is for a specific time. And since there will be certain delay
in arguments, schedule
is more suitable.
I don't think the allow_shoving
function is needed because I don't understand where the limiting of early sending can be useful (the current example doesn't clarify this).
Instead shove
, I can suggest trigger
as an alternative.
In addition to the above, it seems strange to me that we do not use msg_id
in order to get a response to a deferred message. I think there should be a function that accepts msg_id
only (like cancel_deferred
)
I like the idea of schedule
and trigger
. Edited the original comment.
Not sure about triggering allowance. Changed it to deny_triggering
. We can omit it if it is not required at all.
Maybe we should consider argument like is_repeating_task: bool or separate function with the same purpose.
I don't like an idea to have too many parameters. A separate function is better in my opinion.
In addition to the above, it seems strange to me that we do not use msg_id in order to get a response to a deferred message. I think there should be a function that accepts msg_id only (like cancel_deferred)
We have an async function schedule_for_reply
for getting reply. The API of scheduled sending is to be similar to msg::send
et al.
Defer messages sending is 100% must-have-feature, but I'm not sure that other 3 methods are necessary. It also becomes hard to provide such api for the functions: user space should also say on which BN some message id was expected to send
what about just wrapping the whole message:
unsafe {
gstd::config::EXECUTE_MESSAGE_AT = Some(exec::block_timestamp() + self.voting_period);
}
let reply: DaoEvent = msg::send_for_reply(
exec::program_id(),
DaoAction::ProcessProposal(self.proposal_id)),
0,
)
.expect("Error while deferring message")
.await
.expect("Error while processing result");
// ...
what about just wrapping the whole message:
I'm afraid this will yield hidden behavior. It's easy to forget about this setting after using and send a scheduled message instead of the immediate one.