public static Result <ServiceOfflineDurationTracker> Create(
            OperationContext context,
            IClock clock,
            IAbsFileSystem fileSystem,
            int?logIntervalSeconds,
            AbsolutePath logFilePath)
        {
            return(context.PerformOperation(Tracer,
                                            () =>
            {
                if (logIntervalSeconds == null)
                {
                    return new Result <ServiceOfflineDurationTracker>($"{nameof(ServiceOfflineDurationTracker)} is disabled");
                }

                var serviceTracker = new ServiceOfflineDurationTracker(context, clock, fileSystem, logIntervalSeconds.Value, logFilePath);

                // We can't log current timestamp here, because it will mess up with the following GetOfflineDuration call.
                // Instead, the caller of GetOfflineDuration may specify whether to update the file or not.
                return new Result <ServiceOfflineDurationTracker>(serviceTracker);
            }));
        }
        public static Result <ServiceOfflineDurationTracker> Create(
            OperationContext context,
            IClock clock,
            IAbsFileSystem fileSystem,
            DistributedCacheServiceConfiguration configuration)
        {
            return(context.PerformOperation(Tracer,
                                            () =>
            {
                var logIntervalSeconds = configuration.DistributedContentSettings.ServiceRunningLogInSeconds;
                if (logIntervalSeconds == null)
                {
                    return new Result <ServiceOfflineDurationTracker>($"{nameof(ServiceOfflineDurationTracker)} is disabled");
                }

                var logFilePath = configuration.LocalCasSettings.GetCacheRootPathWithScenario(LocalCasServiceSettings.DefaultCacheName) / FileName;

                var serviceTracker = new ServiceOfflineDurationTracker(context, clock, fileSystem, logIntervalSeconds.Value, logFilePath);
                serviceTracker.LogCurrentTimeStampToFile(context);

                return new Result <ServiceOfflineDurationTracker>(serviceTracker);
            }));
        }
        /// <summary>
        /// Creates and runs a distributed cache service
        /// </summary>
        /// <exception cref="CacheException">thrown when cache startup fails</exception>
        public static async Task RunAsync(DistributedCacheServiceArguments arguments)
        {
            // Switching to another thread.
            await Task.Yield();

            var host  = arguments.Host;
            var timer = Stopwatch.StartNew();

            InitializeGlobalLifetimeManager(host);

            // NOTE(jubayard): this is the entry point for running CASaaS. At this point, the Logger inside the
            // arguments holds the client's implementation of our logging interface ILogger. Here, we may override the
            // client's decision with our own.
            // The disposableToken helps ensure that we shutdown properly and all logs are sent to their final
            // destination.
            var loggerReplacement = CreateReplacementLogger(arguments);

            arguments.Logger          = loggerReplacement.Logger;
            using var disposableToken = loggerReplacement.DisposableToken;

            AdjustCopyInfrastructure(arguments);

            var context = new Context(arguments.Logger);

            await ReportStartingServiceAsync(context, host);

            var factory = new CacheServerFactory(arguments);

            var operationContext = new OperationContext(context);
            ServiceOfflineDurationTracker serviceRunningTracker = null;

            // Technically, this method doesn't own the file copier, but no one actually owns it.
            // So to clean up the resources (and print some stats) we dispose it here.
            using (arguments.Copier as IDisposable)
                using (var server = factory.Create())
                {
                    try
                    {
                        var startupResult = await server.StartupAsync(context);

                        if (!startupResult)
                        {
                            throw new CacheException(startupResult.ToString());
                        }

                        var serviceRunningTrackerResult = ServiceOfflineDurationTracker.Create(
                            operationContext,
                            SystemClock.Instance,
                            new PassThroughFileSystem(),
                            arguments.Configuration);

                        ReportServiceStarted(operationContext, host, serviceRunningTrackerResult, timer.Elapsed);

                        serviceRunningTracker = serviceRunningTrackerResult.GetValueOrDefault();
                        await arguments.Cancellation.WaitForCancellationAsync();

                        ReportShuttingDownService(context);
                    }
                    catch (Exception e)
                    {
                        ReportServiceStartupFailed(context, e, timer.Elapsed);
                        throw;
                    }
                    finally
                    {
                        // Writing the current time before shutting the service down.
                        serviceRunningTracker?.LogCurrentTimeStampToFile(operationContext);

                        timer.Reset();
                        var timeoutInMinutes = arguments.Configuration?.DistributedContentSettings?.MaxShutdownDurationInMinutes ?? 30;
                        var result           = await server
                                               .ShutdownAsync(context)
                                               .WithTimeoutAsync("Server shutdown", TimeSpan.FromMinutes(timeoutInMinutes));

                        serviceRunningTracker?.Dispose();
                        ReportServiceStopped(context, host, result, timer.Elapsed);
                    }
                }
        }