Extend Jobbr
Jobbr comes with a comprehensive plugin system, based on the JobbrBuilder
. It’s used by all the plugins available on https://github.com/JobbrIO and can also be leveraged to implement custom additions to the server.
Additional Custom Functionality
The simplest way to create your own component is to immplement the IJobbrComponent
interface and register the type to the JobbrBuilder
. The interface is available in Jobbr.ComponentModel.Registration. You don’t need a dependency to Jobbr and thus should only have dependencies to Component Models.
Sample component
1public class DemoComponent : IJobbrComponent
2{
3 public void Dispose()
4 {
5 }
6
7 public void Start()
8 {
9 }
10
11 public void Stop()
12 {
13 }
14}
Registration
To register the component, you’ll need to register the type to the Jobbr internal DI, which is available through the JobbrBuilder.
1// Add the type to the DI
2builder.Register<IJobbrComponent>(typeof(DemoComponent));
Usually this code is wrapped into an extension method for the IJobbrBuilder, like in the following sample.
DemoComponentExtension.cs
1public static class DemoComponentExtension {
2
3 public static void AddDemoComponent(this IJobbrBuilder builder) {
4
5 // Add the type to the DI
6 builder.Register<IJobbrComponent>(typeof(DemoComponent));
7 }
8}
This allows to easily add your component to any Jobbr that offers a IJobbrBuilder
.
Usage
1var builder = new JobbrBuilder();
2
3builder.AddDemoComponent();
4var server = builder.Create();
Note: Registered types and instances are registered in a Singleton-Scope. Calling
builder.Create()
multiple times can lead to unexpected behavior.
Lifetime
There a three important as state in the interface IJobbrComponent
.
Activation: The component is created when
builder.Create()
is calledStart(): Called when the Jobbr Server is started
Stop(): Called when the Jobbr Server gets started
Dispose(): Called when the instance of JobbrServer gets Disposed
Dependencies
If you like to base on existing services from component implementations or own dependencies you need to specify those in the constructor of your component.
Sample
1public class DemoComponent : IJobbrComponent
2{
3 public void DemoComponent(IQueryService queryService) {
4 this.queryService = queryService;
5 }
6
7 public void Start() {
8 Console.WriteLine($"There are {this.queryService.GetJobRuns().Count} jobruns in the system");
9 }
10
11 /* ... */
12}
Altough it’s possible to inject any available type, (also internal classes) you should only use those services that are defined in the Component Model Packages.
Configuration
In most cases you’ll need to register a settings object to jobbr while setting up and retrieving it in your component. For a storage implementation this might be a configuration how to connect to the database.
You’ll need a settings class like the one below
DemoComponentConfiguration.cs
1public class DemoComponentConfiguration {
2
3 public string DatabaseConnection { get; set; }
4}
An instance of this class needs to be registed to the builder and the DemoComponent’s Constructor needs to be adjusted so that this specific instance is passed to the constructor.
Registering an instance
1var configuration = new DemoComponentConfiguration()
2{
3 DatabaseConnection = "foo"
4};
5
6builder.Add<DemoComponentConfiguration>(configuration));
This is usually done by providing a fluent syntax in the IJobbrBuilder extension from above.
DemoComponentExtension.cs
1public static class DemoComponentExtension {
2
3 public static void AddDemoComponent(this IJobbrBuilder builder, Action<ForkedExecutionConfiguration> config) {
4
5 // Create a new instance of default configuration and pass it to the caller
6 var configuration = new DemoComponentConfiguration()
7 {
8 DatabaseConnection "foo"
9 };
10
11 config?.Invoke(configuration);
12
13 // Register config instance to DI
14 builder.Add<DemoComponentConfiguration>(configuration));
15
16 // Add the type to the DI
17 builder.Register<IJobbrComponent>(typeof(DemoComponent));
18 }
19}
The consumer of the extension then gets a really easy interface to configure your component.
Usage Sample
1var builder = new JobbrBuilder();
2
3builder.AddDemoComponent(c => {
4 c.DatabaseConnection = "something different";
5});
Configuration Validators
You might wan’t to validate the configuration that is passed to your Component before the component is actually activated. This can be done by registering Validators for a given configuration type.
The interface IConfugurationValidator
from Jobbr.ComponentModel.Registration
.
1public interface IConfigurationValidator
2{
3 Type ConfigurationType { get; set; }
4
5 bool Validate(object configuration);
6}
Registration for the imaginary implementation named ConfigurationValiator
.
1// As type
2builder.Register<IConfigurationValidator>(typeof(ConfigurationValidator));
3
4// Or as instance
5builder.Add<IConfigurationValidator>(new ConfigurationValidato()));
Your validator is called for each instance of the specified ConfigurationType
. It’s expected that you either return false in the validation process or throw an exception.
If one validator fails (or returns false), the whole startup process is stopped and the server is in an unrecoverable Error-State.
Replace Core Functionality
Jobbr defines a couple of interfaces that belong to the core functionality. These interfaces are specified in the corresponding component model repositories and packages.
Execution: Contract between an executor and the Jobbr-Server, fulfilled by both the server and a component.
JobStorage: Defines interfaces for storage access
ArtefactStore: Defines interfaces to store and retrieve job related artefacts
These packages are built upon the component infrastructure introduced above. The only different is that you’ll need to implement specific interfaces from these packages instead of the generic IJobbrComponent
.
There are additional component models that define functionality that is available to all components provided by the server implementation
Registration: Boostrapping services, Registration, Validation, Components
Management: Manage the server, Query Jobs, etc.
Plase also see all Component Models on GitHub