Skip to content

firebend/jobba

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

jobba

A durable job scheduling platform for dotnet

Stores

InMemory

The in-memory store is useful for testing and development. It is not recommended for production use.

var jobba = new JobbaBuilder(serviceCollection, "sample")
    .UsingInMemory();

Mongo

To use the Mongo store, install the Jobba.Store.Mongo package

dotnet add package Jobba.Store.Mongo

Then add the following to your JobbaBuilder configuration, providing the connection string and a boolean to enable or disable command logging. There is also an optional third parameter to allow for additional configuration of the Mongo store using the JobbaMongoBuilder.cs.

var jobba = new JobbaBuilder(serviceCollection, "sample")
    .UsingMongo(config.GetConnectionString("MongoDb"), false);

EFCore

To use the EFCore store, install the Jobba.Store.EFCore package

dotnet add package Jobba.Store.EFCore

There are currently 2 supported EF providers maintained by this library.

SqlServer

To use the SqlServer provider, install the Jobba.Store.EFCore.Sql package

dotnet add package Jobba.Store.EFCore.Sql

Then add the following to your JobbaBuilder configuration, providing the connection string, and optional actions to provide additional configuration of the DbContextOptionsBuilder, SqlServerDbContextOptionsBuilder. and the JobbaEfBuilder.cs.

var jobba = new JobbaBuilder(serviceCollection, "sample")
    .UsingSqlServer(config.GetConnectionString("SqlServer"),
                    options =>
                    {
                        options.EnableSensitiveDataLogging();
                        options.EnableDetailedErrors();
                    }, configureBuilder: jb => jb.WithDbInitializer());

Sqlite

To use the Sqlite provider, install the Jobba.Store.EFCore.Sqlite package

dotnet add package Jobba.Store.EFCore.Sqlite

Then add the following to your JobbaBuilder configuration, providing the connection string, and optional actions to provide additional configuration of the DbContextOptionsBuilder, SqliteDbContextOptionsBuilder, and the JobbaEfBuilder.cs.

var jobba = new JobbaBuilder(serviceCollection, "sample")
    .UsingSqlite(config.GetConnectionString("Sqlite"),
                 options =>
                 {
                     options.EnableSensitiveDataLogging();
                     options.EnableDetailedErrors();
                 }, configureBuilder: jb => jb.WithDbInitializer());

Other providers

To use a different EF provider, you will need to manage the configuration and migrations yourself. You can refer to the SqlServer and Sqlite implementations for guidance. JobbaEfBuilderExtensions.cs

Custom

The following interfaces must be registered in the DI container for your custom store:

You can refer to the InMemory implementation for an example of how to implement these interfaces.

Locks

Locking ensures that only one instance of a job is running at a time.

InMemory

The in-memory lock is useful for testing and development. It is registered by default when using the JobbaBuilder. Only use in production if you have a single instance of your application.

Redis

This will use the lit-redis library which will allow for distributed locking across multiple instances of your application.

To use the Redis lock, install the Jobba.Redis package

dotnet add package Jobba.Redis

Then add the following to your JobbaBuilder configuration, providing your connection string.

var jobba = new JobbaBuilder(serviceCollection, "sample")
    .UsingLitRedis(config.GetConnectionString("Redis"));

Custom

The following interface must be registered in the DI container for your custom lock:

You can refer to the InMemory implementation for an example of how to implement this interface.

Event Publishers

Jobba publishes various events to allow for monitoring and logging of job progress.

The events published are:

InMemory

The in-memory event publisher is useful for testing and development. It is registered by default when using the JobbaBuilder. Only use in production if you have a single instance of your application.

MassTransit

This will use the MassTransit library to facilitate event publishing. By using MassTransit, you can publish events to a message broker such as RabbitMQ or Azure Service Bus allowing for distributed event handling.

Custom

The following interface must be registered in the DI container for your custom event publisher:

You must also register consumers for each event published by Jobba. You can refer to the JobbaMassTransitBuilderExtensions.cs for an example of how to implement this interface.

Setup

Check out the Sample project for a working example.

  1. Install the library
<ItemGroup>
   <PackageReference Include="Jobba.Core" />
   <PackageReference Include="Jobba.MassTransit" />
   <PackageReference Include="Jobba.Redis" />
   <PackageReference Include="Jobba.Store.Mongo" />
</ItemGroup>

or

dotnet add package Jobba.Core
dotnet add package Jobba.MassTransit
dotnet add package Jobba.Redis
dotnet add package Jobba.Store.Mongo
  1. Create a new SampleJob class that extends AbstractJobBaseClass. You can also create classes for JobState and JobParameters, or use object as a placeholder
using System;
using System.Threading;
using System.Threading.Tasks;
using Jobba.Core.Abstractions;
using Jobba.Core.Interfaces.Repositories;
using Jobba.Core.Models;
using Microsoft.Extensions.Logging;

namespace Jobba.Sample
{
    public class SampleJobState
    {
        public int Tries { get; set; }
    }

    public class SampleJobParameters
    {
        public string Greeting { get; set; }
    }

    public class SampleJob : AbstractJobBaseClass<SampleJobParameters, SampleJobState> // or use `AbstractJobBaseClass<DefaultJobParams, DefaultJobState>` to not use state or parameters
    {
        private readonly ILogger<SampleJob> _logger;

        public SampleJob(IJobProgressStore progressStore, ILogger<SampleJob> logger) : base(progressStore)
        {
            _logger = logger;
        }

        protected override async Task OnStartAsync(JobStartContext<SampleJobParameters, SampleJobState> jobStartContext, CancellationToken cancellationToken)
        {
            // implement your job's behavior
            var tries = jobStartContext.JobState.Tries + 1;
            _logger.LogInformation("Hey I'm trying! Tries: {Tries} {JobId} {Now}", tries, jobStartContext.JobId, DateTimeOffset.Now);
            await LogProgressAsync(new SampleJobState { Tries = tries }, 50, jobStartContext.JobParameters.Greeting, cancellationToken);
            await Task.Delay(100 * tries, cancellationToken);

            if (tries < 10)
            {
                throw new Exception($"Haven't tried enough {tries}"); // jobba will retry if it encounters an exception
            }
            _logger.LogInformation("Now I'm done!");
        }

        public override string JobName => "Sample Job";
    }
}
  1. In Program.cs, add the jobba configuration to the ConfigureServices callback in CreateHostBuilder
   services
      .AddLogging(o => o.AddSimpleConsole(c => c.TimestampFormat = "[yyyy-MM-dd HH:mm:ss] "))
      .AddJobba(jobba =>
        jobba.UsingMassTransit() // use MassTransit as an event bus
          .UsingMongo("mongodb://localhost:27017/jobba-sample", false)
          .UsingLitRedis("localhost:6379,defaultDatabase=0") // Use LitRedis for distributed locking
          .AddJob<SampleJob, SampleJobParameters, SampleJobState>() // `AddJob<SampleJob, object, object>` if not using state or parameters
        )
      .AddJobbaSampleMassTransit("rabbitmq://guest:guest@localhost/")
      .AddHostedService<SampleHostedService>();

This example uses

  1. Make a service SampleHostedService that extends BackgroundService and injects an IJobScheduler
using System;
using System.Threading;
using System.Threading.Tasks;
using Jobba.Core.Interfaces;
using Jobba.Core.Models;
using Microsoft.Extensions.Hosting;

namespace Jobba.Sample
{
    public class SampleHostedService : BackgroundService
    {
        private readonly IJobScheduler _jobScheduler;

        public SampleHostedService(IJobScheduler jobScheduler)
        {
            _jobScheduler = jobScheduler;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            // create and schedule your job
            var request = new JobRequest<SampleJobParameters, SampleJobState>
            {
                Description = "A Sample Job",
                JobParameters = new SampleJobParameters { Greeting = "Hello" },
                JobType = typeof(SampleJob),
                InitialJobState = new SampleJobState { Tries = 0 },
                JobWatchInterval = TimeSpan.FromSeconds(10),
                MaxNumberOfTries = 100
            };

            await _jobScheduler.ScheduleJobAsync(request, stoppingToken);
        }
    }
}

Usage

ScheduleJobAsync

Create a new JobRequest and schedule it with _jobScheduler in SampleHostedService's ExecuteAsync

   protected override async Task ExecuteAsync(CancellationToken stoppingToken)
   {
      // create a job request
      var request = new JobRequest<SampleJobParameters, SampleJobState>
      {
         Description = "A Sample Job",
         JobParameters = new SampleJobParameters { Greeting = "Hello" },
         JobType = typeof(SampleJob), // the class for the job to run
         InitialJobState = new SampleJobState { Tries = 0 },
         JobWatchInterval = TimeSpan.FromSeconds(10), // time to wait between retries if the job fails
         MaxNumberOfTries = 100 // maximum number of times to retry when a job fails
      };

      // schedule it with the passed-in cancellation token
      await _jobScheduler.ScheduleJobAsync(request, stoppingToken);
   }

CancelJobAsync

Use the job's ID and the provided cancellation token to cancel a scheduled or running job

   protected override async Task ExecuteAsync(CancellationToken stoppingToken)
   {
      // create a job request
      var request = new JobRequest<SampleJobParameters, SampleJobState>
      {
         Description = "A Sample Job",
         JobParameters = new SampleJobParameters { Greeting = "Hello" },
         JobType = typeof(SampleJob), // the class for the job to run
         InitialJobState = new SampleJobState { Tries = 0 },
         JobWatchInterval = TimeSpan.FromSeconds(10), // time to wait between retries if the job fails
         MaxNumberOfTries = 100 // maximum number of times to retry when a job fails
      };

      // schedule it with the passed-in cancellation token
      await _jobScheduler.ScheduleJobAsync(request, stoppingToken);

      // wait a second and cancel the job
      await Task.Delay(TimeSpan.FromSeconds(1), stoppingToken);
      await _jobScheduler.CancelJobAsync(request.Id, stoppingToken);
   }

About

A durable job scheduling platform for dotnet

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages