/// <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); }
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(); }
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}.") }); } }