예제 #1
0
        /// <summary>
        /// Send the provided parcel.
        /// </summary>
        /// <param name="messageBusConnectionConfiguration">Persistence configuration.</param>
        /// <param name="parcel">Parcel to send.</param>
        /// <param name="schedule">Optional recurring schedule.</param>
        public static void Send(
            MessageBusConnectionConfiguration messageBusConnectionConfiguration,
            Parcel parcel,
            ScheduleBase schedule = null)
        {
            new { messageBusConnectionConfiguration }.AsArg().Must().NotBeNull();
            new { parcel }.AsArg().Must().NotBeNull();

            var serializerFactory = SerializerFactory.Instance;

            var envelopeMachine = new EnvelopeMachine(
                PostOffice.MessageSerializerRepresentation,
                serializerFactory);

            var courier = new HangfireCourier(messageBusConnectionConfiguration.CourierPersistenceConnectionConfiguration, envelopeMachine);

            using (var parcelTrackingSystem = new ParcelTrackingSystem(
                       courier,
                       envelopeMachine,
                       messageBusConnectionConfiguration.EventPersistenceConnectionConfiguration,
                       messageBusConnectionConfiguration.ReadModelPersistenceConnectionConfiguration))
            {
                var postOffice = new PostOffice(parcelTrackingSystem, HangfireCourier.DefaultChannelRouter, envelopeMachine);

                if (schedule == null)
                {
                    postOffice.Send(parcel);
                }
                else
                {
                    postOffice.SendRecurring(parcel, schedule);
                }
            }
        }
예제 #2
0
        public static void Launch(
            MessageBusConnectionConfiguration messageBusConnectionConfiguration,
            MessageBusLaunchConfiguration launchConfig,
            IHandlerFactory handlerFactory)
        {
            new { messageBusConnectionConfiguration }.AsArg().Must().NotBeNull();
            new { launchConfig }.AsArg().Must().NotBeNull();
            new { handlerFactory }.AsArg().Must().NotBeNull();

            if (launchConfig.ChannelsToMonitor.Any(_ => _.GetType() != typeof(SimpleChannel)))
            {
                throw new NotSupportedException(Invariant($"Only {nameof(SimpleChannel)}'s are supported as the implementation of {nameof(IChannel)} for {nameof(launchConfig.ChannelsToMonitor)}."));
            }

            var assembliesToRecord = new[] { typeof(HangfireHarnessManager).Assembly }.ToList();

            if (handlerFactory is ReflectionHandlerFactory reflectionHandlerFactory)
            {
                assembliesToRecord.AddRange(reflectionHandlerFactory.FilePathToAssemblyMap.Values);
            }

            var processSiblingAssemblies = assembliesToRecord.Select(SafeFetchAssemblyDetails).ToList();
            var dateTimeOfSampleInUtc    = DateTime.UtcNow;
            var machineDetails           = DomainFactory.CreateMachineDetails();
            var processDetails           = DomainFactory.CreateProcessDetails();

            var diagnosticsTelemetry = new DiagnosticsTelemetry(dateTimeOfSampleInUtc, machineDetails, processDetails, processSiblingAssemblies);

            var serializerFactory = SerializerFactory.Instance;
            var compressorFactory = CompressorFactory.Instance;

            var logProvider = new HangfireLogProviderToNaosLogWritingAdapter();

            LogProvider.SetCurrentLogProvider(logProvider);

            var activeMessageTracker = new InMemoryActiveMessageTracker();

            var envelopeMachine = new EnvelopeMachine(
                PostOffice.MessageSerializerRepresentation,
                serializerFactory);

            var courier = new HangfireCourier(messageBusConnectionConfiguration.CourierPersistenceConnectionConfiguration, envelopeMachine);
            var parcelTrackingSystem = new ParcelTrackingSystem(
                courier,
                envelopeMachine,
                messageBusConnectionConfiguration.EventPersistenceConnectionConfiguration,
                messageBusConnectionConfiguration.ReadModelPersistenceConnectionConfiguration);

            var postOffice = new PostOffice(parcelTrackingSystem, HangfireCourier.DefaultChannelRouter, envelopeMachine);

            HandlerToolshed.InitializePostOffice(() => postOffice);
            HandlerToolshed.InitializeParcelTracking(() => parcelTrackingSystem);
            HandlerToolshed.InitializeSerializerFactory(() => serializerFactory);
            HandlerToolshed.InitializeCompressorFactory(() => compressorFactory);

            var shareManager = new ShareManager(
                serializerFactory);

            var handlerSharedStateMap = new ConcurrentDictionary <Type, object>();

            var dispatcher = new MessageDispatcher(
                handlerFactory,
                handlerSharedStateMap,
                launchConfig.ChannelsToMonitor,
                diagnosticsTelemetry,
                parcelTrackingSystem,
                activeMessageTracker,
                postOffice,
                envelopeMachine,
                shareManager);

            // configure hangfire to use the DispatcherFactory for getting IDispatchMessages calls
            GlobalConfiguration.Configuration.UseActivator(new DispatcherFactoryJobActivator(dispatcher));
            GlobalJobFilters.Filters.Add(new AutomaticRetryAttribute {
                Attempts = launchConfig.MessageDeliveryRetryCount
            });

            var executorOptions = new BackgroundJobServerOptions
            {
                Queues = launchConfig.ChannelsToMonitor.OfType <SimpleChannel>().Select(_ => _.Name).ToArray(),
                SchedulePollingInterval = launchConfig.PollingInterval,
                WorkerCount             = launchConfig.ConcurrentWorkerCount,
            };

            GlobalConfiguration.Configuration.UseSqlServerStorage(
                messageBusConnectionConfiguration.CourierPersistenceConnectionConfiguration.ToSqlServerConnectionString(),
                new SqlServerStorageOptions());

            var launchConfigTimeToLive = launchConfig.TimeToLive;

            if (launchConfigTimeToLive == default(TimeSpan))
            {
                launchConfigTimeToLive = TimeSpan.MaxValue;
            }

            var timeout = DateTime.UtcNow.Add(launchConfigTimeToLive);

            // ReSharper disable once UnusedVariable - good reminder that the server object comes back and that's what is disposed in the end...
            using (var server = new BackgroundJobServer(executorOptions))
            {
                Console.WriteLine(Invariant($"Hangfire Server started. Will terminate when there are no active jobs after: {timeout}."));
                Log.Write(() => new { LogMessage = Invariant($"Hangfire Server launched. Will terminate when there are no active jobs after: {timeout}.") });

                // once the timeout has been achieved with no active jobs the process will exit (this assumes that a scheduled task will restart the process)
                //    the main impetus for this was the fact that Hangfire won't reconnect correctly so we must periodically initiate an entire reconnect.
                while (activeMessageTracker.ActiveMessagesCount != 0 || (DateTime.UtcNow < timeout))
                {
                    Thread.Sleep(launchConfig.PollingInterval);
                }

                Log.Write(() => new { ex = Invariant($"Hangfire Server terminating. There are no active jobs and current time if beyond the timeout:  {timeout}.") });
            }
        }