// A task: a body with a name and a policy, and the message it turns into.
///|
/// A registered body. Sending it writes a message and hands back a handle.
///
/// The argument type is what the body takes; the result type is what it returns,
/// and the handle decodes the stored value back into it. Both go over the wire as
/// JSON, so a task may be sent by one process and run by another.
pub struct Task[A, R] {
app : App
name : String
policy : Policy
run : async (A, Context) -> R
}
///|
/// The name the message carries.
pub fn[A, R] Task::name(self : Task[A, R]) -> String {
self.name
}
///|
/// The policy the registration was given.
pub fn[A, R] Task::policy(self : Task[A, R]) -> Policy {
self.policy
}
///|
/// The message `args` becomes, without publishing it.
fn[A : ToJson, R] Task::compose(
self : Task[A, R],
args : A,
eta? : Int64,
countdown? : Int64,
expires? : Int64,
queue? : String,
priority? : Int32,
id? : String,
) -> @spec.Message {
let now = self.app.now()
let eta = match (eta, countdown) {
(Some(at), _) => Some(at)
(None, Some(delay)) => Some(now + delay)
(None, None) => None
}
{
id: id.unwrap_or(self.app.next_id(self.name)),
name: self.name,
args: Json(args),
queue: queue.unwrap_or(self.policy.queue),
priority: priority.unwrap_or(0),
eta,
expires,
retries: 0,
chain: [],
chord: None,
single_arg: false,
immutable: false,
}
}
///|
/// Publish `args` and return a handle on the run.
///
/// `eta` is when the message may first run and `countdown` is how long from now
/// that is; `eta` wins when both are given, since it is the more specific of the
/// two. `expires` is the time after which running it is pointless: a worker that
/// finds it expired revokes it instead of running it late.
pub async fn[A : ToJson, R : FromJson] Task::send(
self : Task[A, R],
args : A,
eta? : Int64,
countdown? : Int64,
expires? : Int64,
queue? : String,
priority? : Int32,
id? : String,
) -> Handle[R] raise @spec.Refused {
let message = self.compose(
args,
eta?,
countdown?,
expires?,
queue?,
priority?,
id?,
)
self.app.broker.publish(message.queue, message)
Handle::of(self.app, [message.id], false)
}
///|
/// The run of `args` as a node of a canvas, without publishing it.
pub fn[A : ToJson, R] Task::sig(self : Task[A, R], args : A) -> Sig {
Sig::of([self.compose(args)])
}