Custom Executor
Clique offers a wide range of tasks officially for various use cases. If these do not meet your requirements, you can create your own executors to cater to specific tasks seamlessly.
Development Tools
To assist developers in quickly implementing a custom executor, Clique provides Rust procedural macro support. Rust developers can directly use the procedural macros we provide to encapsulate the custom executor. Developers do not need to be concerned with how the executor interacts with the Clique network; they only need to focus on their own computational logic.
First, include the following dependencies in your Rust project:
clique-proc-macro = { git = "https://github.com/CliqueOfficial/clique-protocol-sdk" }
clique = { git = "https://github.com/CliqueOfficial/clique-protocol-sdk" }Clique provides the following procedural macros:
#[namespace(name = ...)]The
namespacemacro ensures that all tasks within the annotated module are grouped under a specific namespace, and the namespace is corresbonding to thenamein the Clique Task Manifest. For example, if the task's name is "clique_httpsRequest," then the namespace should be specified as "clique."
#[task]The
taskmacro is used to define a task struct. This macro annotates a struct that represents a task, allowing it to be recognized and managed by the task execution system.You need to implement the
clique::Tasktrait for the struct marked with thetaskmacro, and within theexecutemethod, implement your actual computational logic. Note that the input and output of theexecutemethod are Rust struct generated based on theinputandoutputsection of your Clique Task Manifest file. You can directly use the field name from the manifest to access the corresbonding field in the input / output.
#[clique::async_trait]This macro is used to annotate the implementation of
clique::Tasktrait, since this trait isasync
#[executor(with(...))]The
executormacro is used to define an executor struct that can handle the execution of multiple task modules. In thewithfield, fill in the name of the module decorated with thenamespacemacro. The tasks within these modules will be imported into your custom executor.
Here is an example:
use clique_proc_macro::{executor, namespace};
#[namespace(name = "yourOrganization")]
pub mod task_mod1 {
#[task]
pub struct HttpsRequest;
#[clique::async_trait]
impl clique::Task for HttpsRequest {
type Error = anyhow::Error;
async fn execute(
input: Self::Input,
) -> Result<Self::Output, Self::Error> {
let url = input.url;
let encoding = input.encoding;
for transformation in encoding.into_iter() {
let json_ptr_str: String = transformation.from;
let soltype_str: String = transformation.soltype;
// ...
}
let response: Vec<u8> = // ...
let output = HttpsRequestOutput { response };
Ok(output)
}
}
#[task]
pub struct HttpsRequest2;
#[clique::async_trait]
impl clique::Task for HttpsRequest2 {
type Error = anyhow::Error;
async fn execute(
input: Self::Input,
) -> Result<Self::Output, Self::Error> {
// ...
}
}
}
#[namespace(name = "yourOrganization")]
pub mod task_mod2 {
#[task]
pub struct AnotherTask;
#[clique::async_trait]
impl clique::Task for AnotherTask {
type Error = anyhow::Error;
async fn execute(
input: Self::Input,
) -> Result<Self::Output, Self::Error> {
// ...
}
}
}
#[executor(with(
task_mod1,
task_mod2,
))]
pub struct MyCustomExecutor;Last updated