Closed drewstone closed 2 weeks ago
Just provide the DefaultRunner
with a builder pattern where it takes a list of Event Handlers.
A better approach could be a macro similar to #[tokio::main]
that we could build to improve the DX:
#[sdk::main]
async fn main(config: StdGadgetConfiguration) -> sdk::Result<()> {
// ...
}
Here is another proposal that I though about last night
This proposal aims to introduce a Dependency Injection (DI) system in the Gadget framework, inspired by the DI implementation in the Axum web framework. The goal is to enhance the modularity and extensibility of the Gadget framework by allowing jobs to automatically register and resolve dependencies.
Jobs in the Gadget framework will be defined the same way we are currently have, with the job attribute macro. Since jobs are very similar to Axum's handlers, we could take that fact and have trait Job
similar to the Handler
trait in axum.
Example:
#[job(id = 1, params(x, y), result(_))]
async fn my_job(Context(ctx): Context<MyContext>, x: u64, y: u64) -> Result<u64, Inflatable> {
// Job implementation ..
}
The Job trait would be defined as following:
pub trait Job<T, C>: Clone + Send + Sized + 'static {
type Out: Into<Field>;
/// The type of future calling this job returns.
type Future: Future<Output = Self::Out> + Send + 'static;
/// Call the handler with the given request.
fn call(self, params: &[Field], ctx: C) -> Self::Future;
/// Convert the job fn into a [`JobHandler`] by providing the context
fn with_context(self, ctx: C) -> JobHandler<Self, T, C> {
JobHandler::new(self, ctx)
}
}
The we would implement this trait for anything that adheres to the following:
async fn
Send
.IntoField
An environment setup function will be introduced to register jobs and their contexts. This function will manage the lifecycle of the jobs and ensure that dependencies are resolved correctly.
Example:
let my_ctx = MyContext {
// ...
};
env.with_context(my_ctx)
.job(my_job)
.job(my_other_job)
.run().await?;
That's it, the job
method in the env
accepts anything that implements the Job
trait, which is all #[job]
implements that by default, then it will pass all of them when we call run()
to their events watchers to do job.call(...)
.
Integrating a DI system similar to Axum's in the Gadget framework will significantly enhance its modularity and ease of use. By automatically registering and resolving job dependencies, we can streamline the development process and improve the overall robustness of the framework.
Feel free to ask me any questions.
Overview
Every blueprint
main.rs
needs to re-implement repetitive run and registration code which oftentimes has only a few minor differences across different blueprints. This should be abstracted and put into the SDK. The custom configuration should be injected through the exposed structs or environment so that there is less code needed to get a blueprint deployed and running.https://github.com/webb-tools/gadget/tree/drew/gadget-runner