HangfireIO / Hangfire.InMemory

In-memory job storage for Hangfire with an efficient implementation
Other
73 stars 16 forks source link

Job not started #11

Closed EgoPingvina closed 1 year ago

EgoPingvina commented 1 year ago

I tried to create a simple example with Hangfire and InMemory storage. But it does not fire background jobs. Firstly I thought that problem was with cron, but even with * * * * * or Cron.Minutely() it does not work.

Nuget packages: image

My code:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using Hangfire;

namespace TestHangfire
{
    public static class Program
    {
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((context, options) =>
                {
                    options.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
                           .AddEnvironmentVariables();
                })
                .ConfigureServices((context, services) =>
                {
                    services.AddHangfire(conf =>
                        conf.UseColouredConsoleLogProvider()
                            .UseInMemoryStorage());

                    services.AddHangfireServer(options =>
                    {
                        options.ServerName = "Test.Hangfire";
                    });

                    var provider = services.BuildServiceProvider();

                    var recurringJob = provider.GetRequiredService<IRecurringJobManager>();
                        recurringJob.AddOrUpdate<TestJob>(
                            "TestJob",
                            job => job.Execute(),
                            "* * * * *");

                    var recurringJob2 = provider.GetRequiredService<IRecurringJobManager>();
                        recurringJob2.AddOrUpdate(
                        "TestJob2",
                        () => Console.WriteLine("Second job triggered!"),
                        Cron.Minutely());
                });

        public static void Main(string[] args)
            => CreateHostBuilder(args)
               .Build()
               .Run();
    }

    public sealed class TestJob
    {
        public void Execute()
        {
            Console.WriteLine(
                $"Сообщение, сформированное в {DateTime.UtcNow}");
        }
    }
}

What did I do wrong?

EgoPingvina commented 1 year ago

And how can I get status/count/any info about created jobs from InMemory storage?

EgoPingvina commented 1 year ago

If replace InMemory with MsSqlServer

                    services.AddHangfire(conf =>
                        conf.SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
                            .UseSimpleAssemblyNameTypeSerializer()
                            .UseRecommendedSerializerSettings()
                            .UseColouredConsoleLogProvider()
                            .UseSqlServerStorage(@"Server=localhost;Database=Hangfire;Integrated Security=SSPI;Encrypt = True; Trust Server Certificate=true;"));

it works.

In other words, the problem exactly is in the storage used.

odinserj commented 1 year ago

The problem is that application services are built twice:

// here
=> CreateHostBuilder(args)
               .Build()

// and here
var provider = services.BuildServiceProvider();

So two in-memory storages are being created here, and recurring jobs go to one, and servers listen for another – that's why recurring jobs aren't being run. Please try to move recurring job creation logic to the Main method, instead of using it in the Configure method.

SQL Server storage is working only because it's a shared storage even if multiple SqlServerStorage class instances created.

EgoPingvina commented 1 year ago

This helped, thanks! Now both jobs are executed.

Here's a working example in case anyone runs into the same problem:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using Hangfire;

namespace TestHangfire
{
    public static class Program
    {
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((context, options) =>
                {
                    options.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
                           .AddEnvironmentVariables();
                })
                .ConfigureServices((context, services) =>
                {
                    services.AddHangfire(conf =>
                        conf
                            .UseColouredConsoleLogProvider()
                            .UseInMemoryStorage());

                    services.AddHangfireServer(options =>
                    {
                        options.ServerName = "Test.Hangfire";
                    });
                });

        public static void Main(string[] args)
        {
            var app =
            CreateHostBuilder(args)
               .Build();

            using (var scope = app.Services.CreateScope())
            {
                var provider = scope.ServiceProvider;

                var recurringJob = provider.GetRequiredService<IRecurringJobManager>();
                recurringJob.AddOrUpdate<TestJob>(
                    "TestJob",
                    job => job.Execute(),
                    "* * * * *");

                var recurringJob2 = provider.GetRequiredService<IRecurringJobManager>();
                recurringJob2.AddOrUpdate(
                    "TestJob2",
                    () => Console.WriteLine("Вторая джоба"),
                    Cron.Minutely());
            }

            app.Run();
        }
    }

    public sealed class TestJob
    {
        public void Execute()
        {
            Console.WriteLine(
                $"Сообщение, сформированное в {DateTime.UtcNow}");
        }
    }
}
odinserj commented 1 year ago

You can also create it as an empty web application and setup the Dashboard UI to have some visibility into your jobs, please see https://docs.hangfire.io/en/latest/getting-started/aspnet-core-applications.html

EgoPingvina commented 1 year ago

You can also create it as an empty web application and setup the Dashboard UI to have some visibility into your jobs, please see https://docs.hangfire.io/en/latest/getting-started/aspnet-core-applications.html

Okay, I'll definitely take a look. Thanks again for the quick and detailed response!