Beispiel #1
0
        /// <summary>
        /// This is a static method to run a job whose args are passed in
        /// By default,
        ///     a) The job will be run continuously in a while loop. Could be overridden using 'once' argument
        ///     b) The sleep duration between each run when running continuously is 5000 milliSeconds. Could be overridden using '-Sleep' argument
        /// </summary>
        /// <param name="job">Job to run</param>
        /// <param name="commandLineArgs">Args contains args to the job runner like (dbg, once and so on) and for the job itself</param>
        /// <returns></returns>
        public static async Task Run(JobBase job, string[] commandLineArgs)
        {
            if (commandLineArgs.Length > 0 && string.Equals(commandLineArgs[0], "-dbg", StringComparison.OrdinalIgnoreCase))
            {
                commandLineArgs = commandLineArgs.Skip(1).ToArray();
                Debugger.Launch();
            }

            bool consoleLogOnly = false;
            if (commandLineArgs.Length > 0 && string.Equals(commandLineArgs[0], "-ConsoleLogOnly", StringComparison.OrdinalIgnoreCase))
            {
                commandLineArgs = commandLineArgs.Skip(1).ToArray();
                consoleLogOnly = true;
            }

            // Set JobTraceListener. This will be done on every job run as well
            SetJobTraceListener(job, consoleLogOnly);
            try
            {
                Trace.TraceInformation("Started...");

                // Get the args passed in or provided as an env variable based on jobName as a dictionary of <string argName, string argValue>
                var jobArgsDictionary = JobConfigurationManager.GetJobArgsDictionary(job.JobTraceListener, commandLineArgs, job.JobName);

                bool runContinuously = !JobConfigurationManager.TryGetBoolArgument(jobArgsDictionary, JobArgumentNames.Once);
                int? sleepDuration = JobConfigurationManager.TryGetIntArgument(jobArgsDictionary, JobArgumentNames.Sleep);

                // Setup the job for running
                JobSetup(job, jobArgsDictionary, ref sleepDuration);

                // Run the job loop
                await JobLoop(job, runContinuously, sleepDuration.Value, consoleLogOnly);
            }
            catch (AggregateException ex)
            {
                var innerEx = ex.InnerExceptions.Count > 0 ? ex.InnerExceptions[0] : null;
                if (innerEx != null)
                {
                    Trace.TraceError("[FAILED]: " + innerEx);
                }
                else
                {
                    Trace.TraceError("[FAILED]: " + ex);
                }
            }
            catch (Exception ex)
            {
                Trace.TraceError("[FAILED]: " + ex);
            }

            // Call FlushAll here. This is VERY IMPORTANT
            // Exception message(s) when the job faults are still in the queue. Need to be flushed
            // Also, when the job is only run once, FlushAll is important again
            job.JobTraceListener.Close();
        }
Beispiel #2
0
 private static void SetJobTraceListener(JobBase job, bool consoleLogOnly)
 {
     if(consoleLogOnly)
     {
         job.SetJobTraceListener(new JobTraceListener());
         Trace.TraceWarning("You have chosen not to log messages to Azure blob storage. Note that this is NOT recommended");
     }
     else
     {
         job.SetJobTraceListener(new AzureBlobJobTraceListener(job.JobName));
     }
 }
Beispiel #3
0
        private static void JobSetup(JobBase job, IDictionary<string, string> jobArgsDictionary, ref int? sleepDuration)
        {
            if (JobConfigurationManager.TryGetBoolArgument(jobArgsDictionary, "dbg"))
            {
                throw new ArgumentException("-dbg is a special argument and should be the first argument...");
            }

            if (JobConfigurationManager.TryGetBoolArgument(jobArgsDictionary, "ConsoleLogOnly"))
            {
                throw new ArgumentException("-ConsoleLogOnly is a special argument and should be the first argument (can be the second if '-dbg' is used)...");
            }

            if (sleepDuration == null)
            {
                Trace.TraceWarning("SleepDuration is not provided or is not a valid integer. Unit is milliSeconds. Assuming default of 5000 ms...");
                sleepDuration = 5000;
            }

            // Initialize the job once with everything needed.
            // JobTraceListener(s) are already initialized
            if (!job.Init(jobArgsDictionary))
            {
                // If the job could not be initialized successfully, STOP!
                Trace.TraceError("Exiting. The job could not be initialized successfully with the arguments passed");
            }
        }
Beispiel #4
0
        private static async Task<string> JobLoop(JobBase job, bool runContinuously, int sleepDuration, bool consoleLogOnly)
        {
            // Run the job now
            var stopWatch = new Stopwatch();
            bool success;

            while (true)
            {
                Trace.WriteLine("Running " + (runContinuously ? " continuously..." : " once..."));
                Trace.WriteLine("SleepDuration is " + PrettyPrintTime(sleepDuration));
                Trace.WriteLine("Job run started...");

                // Force a flush here to create a blob corresponding to run indicating that the run has started
                job.JobTraceListener.Flush();

                stopWatch.Restart();
                success = await job.Run();
                stopWatch.Stop();

                Trace.WriteLine("Job run ended...");
                Trace.TraceInformation("Job run took {0}", PrettyPrintTime(stopWatch.ElapsedMilliseconds));
                if(success)
                {
                    Trace.TraceInformation(_jobSucceeded);
                }
                else
                {
                    Trace.TraceWarning(_jobFailed);
                }

                // At this point, FlushAll is not called, So, what happens when the job is run only once?
                // Since, FlushAll is called right at the end of the program, this is no issue
                if (!runContinuously)
                {
                    break;
                }

                // Wait for <sleepDuration> milliSeconds and run the job again
                Trace.WriteLine(string.Format("Will sleep for {0} before the next Job run", PrettyPrintTime(sleepDuration)));

                // Flush All the logs for this run
                job.JobTraceListener.Close();

                // Use Console.WriteLine when you don't want it to be logged in Azure blobs
                Console.WriteLine("Sleeping for {0} before the next job run", PrettyPrintTime(sleepDuration));
                Thread.Sleep(sleepDuration);

                SetJobTraceListener(job, consoleLogOnly);
            }

            return success ? _jobSucceeded : _jobFailed;
        }
        private static async Task <int> Run(JobBase job, string[] commandLineArgs, bool?runContinuously)
        {
            if (commandLineArgs.Length > 0 && string.Equals(commandLineArgs[0], "-" + JobArgumentNames.Dbg, StringComparison.OrdinalIgnoreCase))
            {
                commandLineArgs = commandLineArgs.Skip(1).ToArray();
                Debugger.Launch();
            }

            // Configure logging before Application Insights is enabled.
            // This is done so, in case Application Insights fails to initialize, we still see output.
            var loggerFactory = ConfigureLogging(job);

            int exitCode;

            try
            {
                _logger.LogInformation("Started...");

                // Get the args passed in or provided as an env variable based on jobName as a dictionary of <string argName, string argValue>
                var jobArgsDictionary = JobConfigurationManager.GetJobArgsDictionary(
                    ServiceContainer,
                    loggerFactory.CreateLogger(typeof(JobConfigurationManager)),
                    commandLineArgs);

                // Determine job and instance name, for logging.
                var jobName      = job.GetType().Assembly.GetName().Name;
                var instanceName = JobConfigurationManager.TryGetArgument(jobArgsDictionary, JobArgumentNames.InstanceName) ?? jobName;
                TelemetryConfiguration.Active.TelemetryInitializers.Add(new JobNameTelemetryInitializer(jobName, instanceName));

                // Setup logging
                if (!ApplicationInsights.Initialized)
                {
                    string instrumentationKey = JobConfigurationManager.TryGetArgument(jobArgsDictionary, JobArgumentNames.InstrumentationKey);
                    if (!string.IsNullOrWhiteSpace(instrumentationKey))
                    {
                        ApplicationInsights.Initialize(instrumentationKey);
                    }
                }

                // Configure our logging again with Application Insights initialized.
                loggerFactory = ConfigureLogging(job);

                var hasOnceArgument = JobConfigurationManager.TryGetBoolArgument(jobArgsDictionary, JobArgumentNames.Once);

                if (runContinuously.HasValue && hasOnceArgument)
                {
                    _logger.LogWarning(
                        $"This job is designed to {(runContinuously.Value ? "run continuously" : "run once")} so " +
                        $"the -{JobArgumentNames.Once} argument is {(runContinuously.Value ? "ignored" : "redundant")}.");
                }

                runContinuously = runContinuously ?? !hasOnceArgument;
                var reinitializeAfterSeconds = JobConfigurationManager.TryGetIntArgument(jobArgsDictionary, JobArgumentNames.ReinitializeAfterSeconds);
                var sleepDuration            = JobConfigurationManager.TryGetIntArgument(jobArgsDictionary, JobArgumentNames.Sleep); // sleep is in milliseconds

                if (!sleepDuration.HasValue)
                {
                    sleepDuration = JobConfigurationManager.TryGetIntArgument(jobArgsDictionary, JobArgumentNames.Interval);
                    if (sleepDuration.HasValue)
                    {
                        sleepDuration = sleepDuration.Value * 1000; // interval is in seconds
                    }
                }

                if (!sleepDuration.HasValue)
                {
                    if (runContinuously.Value)
                    {
                        _logger.LogInformation("SleepDuration is not provided or is not a valid integer. Unit is milliSeconds. Assuming default of 5000 ms...");
                    }

                    sleepDuration = 5000;
                }
                else if (!runContinuously.Value)
                {
                    _logger.LogWarning(
                        $"The job is designed to run once so the -{JobArgumentNames.Sleep} and " +
                        $"-{JobArgumentNames.Interval} arguments are ignored.");
                }

                if (!reinitializeAfterSeconds.HasValue)
                {
                    _logger.LogInformation(
                        $"{JobArgumentNames.ReinitializeAfterSeconds} command line argument is not provided or is not a valid integer. " +
                        "The job will reinitialize on every iteration");
                }
                else if (!runContinuously.Value)
                {
                    _logger.LogWarning(
                        $"The job is designed to run once so the -{JobArgumentNames.ReinitializeAfterSeconds} " +
                        $"argument is ignored.");
                }

                // Ensure that SSLv3 is disabled and that Tls v1.2 is enabled.
                ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Ssl3;
                ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

                // Run the job loop
                exitCode = await JobLoop(job, runContinuously.Value, sleepDuration.Value, reinitializeAfterSeconds, jobArgsDictionary);
            }
            catch (Exception ex)
            {
                exitCode = 1;
                _logger.LogError("Job runner threw an exception: {Exception}", ex);
            }

            Trace.Close();
            TelemetryConfiguration.Active.TelemetryChannel.Flush();

            return(exitCode);
        }
 /// <summary>
 /// This is a static method to run a job whose args are passed in
 /// By default,
 ///     a) The job will be run the job once, irrespective of the 'once' argument.
 ///     b) The sleep duration between each run when running continuously is 5000 milliSeconds. Could be overridden using '-Sleep' argument
 /// </summary>
 /// <param name="job">Job to run</param>
 /// <param name="commandLineArgs">Args contains args to the job runner like (dbg, once and so on) and for the job itself</param>
 /// <returns>The exit code, where 0 indicates success and non-zero indicates an error.</returns>
 public static async Task <int> RunOnce(JobBase job, string[] commandLineArgs)
 {
     return(await Run(job, commandLineArgs, runContinuously : false));
 }
        private static async Task <int> JobLoop(
            JobBase job,
            bool runContinuously,
            int sleepDuration,
            int?reinitializeAfterSeconds,
            IDictionary <string, string> jobArgsDictionary)
        {
            // Run the job now
            var       stopWatch = new Stopwatch();
            Stopwatch timeSinceInitialization = null;

            int exitCode;

            while (true)
            {
                _logger.LogInformation("Running {RunType}", (runContinuously ? " continuously..." : " once..."));
                _logger.LogInformation("SleepDuration is {SleepDuration}", PrettyPrintTime(sleepDuration));
                _logger.LogInformation("Job run started...");

                var initialized = false;
                stopWatch.Restart();

                try
                {
                    if (ShouldInitialize(reinitializeAfterSeconds, timeSinceInitialization))
                    {
                        job.Init(ServiceContainer, jobArgsDictionary);
                        timeSinceInitialization = Stopwatch.StartNew();
                    }

                    initialized = true;

                    await job.Run();

                    exitCode = 0;
                    _logger.LogInformation(JobSucceeded);
                }
                catch (Exception e)
                {
                    exitCode = 1;
                    _logger.LogError("{JobState}: {Exception}", initialized ? JobFailed : JobUninitialized, e);
                }
                finally
                {
                    _logger.LogInformation("Job run ended...");
                    stopWatch.Stop();
                    _logger.LogInformation("Job run took {RunDuration}", PrettyPrintTime(stopWatch.ElapsedMilliseconds));
                }

                if (!runContinuously)
                {
                    // It is ok that we do not flush the logs here.
                    // Logs will be flushed at the end of Run().
                    break;
                }

                // Wait for <sleepDuration> milliSeconds and run the job again
                _logger.LogInformation("Will sleep for {SleepDuration} before the next Job run", PrettyPrintTime(sleepDuration));

                await Task.Delay(sleepDuration);
            }

            return(exitCode);
        }
Beispiel #8
0
        /// <summary>
        /// This is a static method to run a job whose args are passed in
        /// By default,
        ///     a) The job will be run continuously in a while loop. Could be overridden using 'once' argument
        ///     b) The sleep duration between each run when running continuously is 5000 milliSeconds. Could be overridden using '-Sleep' argument
        /// </summary>
        /// <param name="job">Job to run</param>
        /// <param name="commandLineArgs">Args contains args to the job runner like (dbg, once and so on) and for the job itself</param>
        /// <returns></returns>
        public static async Task Run(JobBase job, string[] commandLineArgs)
        {
            if (commandLineArgs.Length > 0 && string.Equals(commandLineArgs[0], "-" + JobArgumentNames.Dbg, StringComparison.OrdinalIgnoreCase))
            {
                commandLineArgs = commandLineArgs.Skip(1).ToArray();
                Debugger.Launch();
            }

            // Configure logging before Application Insights is enabled.
            // This is done so, in case Application Insights fails to initialize, we still see output.
            var loggerFactory = ConfigureLogging(job);

            try
            {
                _logger.LogInformation("Started...");

                // Get the args passed in or provided as an env variable based on jobName as a dictionary of <string argName, string argValue>
                var jobArgsDictionary = JobConfigurationManager.GetJobArgsDictionary(loggerFactory.CreateLogger(typeof(JobConfigurationManager)), commandLineArgs, job.JobName, (ISecretReaderFactory)ServiceContainer.GetService(typeof(ISecretReaderFactory)));

                // Setup logging
                if (!ApplicationInsights.Initialized)
                {
                    string instrumentationKey = JobConfigurationManager.TryGetArgument(jobArgsDictionary, JobArgumentNames.InstrumentationKey);
                    if (!string.IsNullOrWhiteSpace(instrumentationKey))
                    {
                        ApplicationInsights.Initialize(instrumentationKey);
                    }
                }

                // Configure our logging again with Application Insights initialized.
                loggerFactory = ConfigureLogging(job);

                var runContinuously = !JobConfigurationManager.TryGetBoolArgument(jobArgsDictionary, JobArgumentNames.Once);
                var sleepDuration   = JobConfigurationManager.TryGetIntArgument(jobArgsDictionary, JobArgumentNames.Sleep); // sleep is in milliseconds
                if (!sleepDuration.HasValue)
                {
                    sleepDuration = JobConfigurationManager.TryGetIntArgument(jobArgsDictionary, JobArgumentNames.Interval);
                    if (sleepDuration.HasValue)
                    {
                        sleepDuration = sleepDuration.Value * 1000; // interval is in seconds
                    }
                }

                if (sleepDuration == null)
                {
                    _logger.LogInformation("SleepDuration is not provided or is not a valid integer. Unit is milliSeconds. Assuming default of 5000 ms...");
                    sleepDuration = 5000;
                }

                // Ensure that SSLv3 is disabled and that Tls v1.2 is enabled.
                ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Ssl3;
                ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

                // Run the job loop
                await JobLoop(job, runContinuously, sleepDuration.Value, jobArgsDictionary);
            }
            catch (Exception ex)
            {
                _logger.LogError("Job runner threw an exception: {Exception}", ex);
            }
        }
Beispiel #9
0
 /// <summary>
 /// This is a static method to run a job whose args are passed in
 /// By default,
 ///     a) The job will be run continuously in a while loop. Could be overridden using 'once' argument
 ///     b) The sleep duration between each run when running continuously is 5000 milliSeconds. Could be overridden using '-Sleep' argument
 /// </summary>
 /// <param name="job">Job to run</param>
 /// <param name="commandLineArgs">Args contains args to the job runner like (dbg, once and so on) and for the job itself</param>
 /// <returns></returns>
 public static async Task Run(JobBase job, string[] commandLineArgs)
 {
     await Run(job, commandLineArgs, runContinuously : null);
 }