同时在多台服务器上运行一个作业队列

时间:2021-05-06 09:44:53

标签: c# .net-core hangfire

我有一个有两台服务器的真实场景。我有一个队列,我只想在两台服务器之一上同时运行一项作业。但看起来两台服务器都在尝试处理这项工作。有可能吗?

我的代码不起作用。要求是,如果一台服务器运行一项作业,另一台服务器不应放入队列而是忘记。在实际场景中,我需要将其分布在多台服务器上。

可能的存储只能是 Redis 和 PostgreSQL。

有关如何解决此问题的任何想法?

using System.Threading;
using System.Threading.Tasks;
using Hangfire;
using Hangfire.Logging;
using Hangfire.Logging.LogProviders;
using Hangfire.MemoryStorage;
using Hangfire.MemoryStorage.Database;
using Hangfire.PostgreSql;
using Hangfire.Pro.Redis;

namespace HangfireLockQueue
{
    public class Program
    {
        static void Main(string[] args)
        {
            // 1.memory
            //JobStorage storage = new MemoryStorageFake(new MemoryStorageOptions());

            // 2.redis
            //JobStorage storage = new RedisStorage("redis:6379,ssl = false", new RedisStorageOptions
            //{
            //    Prefix = "HangfireRedis-Local:"
            //});

            // 3.postgres
            var connectionString = "Host=postgres;Database=scheduler;Username=test;Password=<>;";
            JobStorage storage = new PostgreSqlStorage(connectionString, new PostgreSqlStorageOptions
            {
                InvisibilityTimeout = TimeSpan.FromMinutes(5),
                QueuePollInterval = TimeSpan.FromMilliseconds(200),
                DistributedLockTimeout = TimeSpan.FromSeconds(10),
            });

            JobStorage.Current = storage;
            Console.WriteLine(JobStorage.Current);

            LogProvider.SetCurrentLogProvider(new ColouredConsoleLogProvider());

            RunServer1(storage);
            RunServer2(storage);

            Console.ReadLine();
        }

        private static void RunServer1(JobStorage storage)
        {
            Task.Factory.StartNew(() => RunServer1Client1Queue(storage));
        }

        private static void RunServer1Client1Queue(JobStorage storage)
        {
            var serverOptions = new BackgroundJobServerOptions
            {
                ShutdownTimeout = TimeSpan.FromMinutes(5),
                ServerName = $"{Environment.MachineName}1.{Guid.NewGuid()}",
                Queues = new[] { "queue1" },
                WorkerCount = 1
            };

            using (new BackgroundJobServer(serverOptions, storage))
            {
                Log("Hangfire Server 1 started. Press any key to exit...");

                RecurringJob.AddOrUpdate(
                    Guid.NewGuid().ToString(),
                    () => JobThree(),
                    "* * * * *",
                    queue: "queue1");

                Console.ReadKey();
            }
        }

        private static void RunServer2(JobStorage storage)
        {
            Task.Factory.StartNew(() => RunServer2Client1Queue(storage));
        }

        private static void RunServer2Client1Queue(JobStorage storage)
        {
            Thread.Sleep(2000);
            var serverOptions = new BackgroundJobServerOptions
            {
                ShutdownTimeout = TimeSpan.FromMinutes(5),
                ServerName = $"{Environment.MachineName}2.{Guid.NewGuid()}",
                Queues = new[] { "queue1" },
                WorkerCount = 1
            };

            using (new BackgroundJobServer(serverOptions, storage))
            {
                Log("Hangfire Server 2 started. Press any key to exit...");

                RecurringJob.AddOrUpdate(
                    Guid.NewGuid().ToString(),
                    () => JobThree(),
                    "* * * * *",
                    queue: "queue1");

                Console.ReadKey();
            }
        }

        public static void JobThree()
        {
            // implement guard if not working
            Thread.Sleep(3000);
            Log($"JobThree, current time:{DateTime.Now.ToString()}");
        }

        public static void Log(string msg, LogLevel level = LogLevel.Info)
        {
            LogProvider.GetLogger("Main").Log(level, () => { return msg; });
        }
    }
}

0 个答案:

没有答案