/// <summary>
        /// Build and write standard telemetry items to  <see cref="Its.Log" />.
        /// </summary>
        protected static void WriteStandardTelemetry()
        {
            /*---------------------------------------------------------------------------*
            * Write telemetry:  Log telemetry general records                           *
            *---------------------------------------------------------------------------*/
            var dateTimeOfSampleInUtc = DateTime.UtcNow;
            var machineDetails        = DomainFactory.CreateMachineDetails();
            var processDetails        = DomainFactory.CreateProcessDetails();

            var processDirectory         = Path.GetDirectoryName(processDetails.FilePath) ?? throw new InvalidOperationException("Could not get directory from process file path: " + processDetails.FilePath);
            var processSiblingAssemblies = Directory.GetFiles(processDirectory, "*", SearchOption.AllDirectories)
                                           .Where(_ => _.ToLowerInvariant().EndsWith(".exe") || _.ToLowerInvariant().EndsWith(".dll")).Select(_ =>
            {
                try
                {
                    return(AssemblyDetails.CreateFromFile(_));
                }
                catch (Exception)
                {
                    return(new AssemblyDetails(Path.ChangeExtension(Path.GetFileName(_), string.Empty), Version.Parse("1.0.0.0").ToString(), _, "UNKNOWN"));
                }
            })
                                           .ToList();

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

            Its.Log.Instrumentation.Log.Write(() => diagnosticsTelemetry);
        }
Пример #2
0
        public static void TestCreate()
        {
            // arrange
            var machineNameKinds = EnumExtensions.GetAllPossibleEnumValues <MachineNameKind>().Select(_ => _.ToString());

            // act
            var details         = DomainFactory.CreateMachineDetails();
            var availableMemory = MachineMemory.GetMachineMemoryInGb()[MachineMemoryKind.AvailablePhysical];

            // assert
            details.Should().NotBeNull();
            details.OperatingSystem.Should().NotBeNull();
            details.ClrVersion.Should().NotBeNullOrWhiteSpace();
            availableMemory.Should().BeLessThan(details.GetTypedMemoryKindToValueInGbMap()[MachineMemoryKind.TotalPhysical]);

            details.MachineNameKindToNameMap.Keys.SymmetricDifference(machineNameKinds).Any().Should().BeFalse();
            details.MachineNameKindToNameMap.Values.Any(string.IsNullOrWhiteSpace).Should().BeFalse();
        }
Пример #3
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}.") });
            }
        }