private void CacheJobBinaries(JobBase job, IJobLogger logger) { bool isInPlaceDefault = job.ScriptHost.GetType() == typeof(NodeScriptHost); if (JobSettings.GetIsInPlace(isInPlaceDefault)) { _inPlaceWorkingDirectory = JobBinariesPath; SafeKillAllRunningJobInstances(logger); UpdateAppConfigs(WorkingDirectory); return; } _inPlaceWorkingDirectory = null; if (WorkingDirectory != null) { try { int currentHash = CalculateHashForJob(JobBinariesPath); int lastHash = CalculateHashForJob(WorkingDirectory); if (lastHash == currentHash) { return; } } catch (Exception ex) { // Log error and ignore it as it's not critical to cache job binaries logger.LogWarning("Failed to calculate hash for WebJob, continue to copy WebJob binaries (this will not affect WebJob run)\n" + ex); _analytics.UnexpectedException(ex); } } SafeKillAllRunningJobInstances(logger); if (FileSystemHelpers.DirectoryExists(JobTempPath)) { FileSystemHelpers.DeleteDirectorySafe(JobTempPath, ignoreErrors: true); } if (FileSystemHelpers.DirectoryExists(JobTempPath)) { logger.LogWarning("Failed to delete temporary directory"); } try { OperationManager.Attempt(() => { var tempJobInstancePath = Path.Combine(JobTempPath, Path.GetRandomFileName()); FileSystemHelpers.CopyDirectoryRecursive(JobBinariesPath, tempJobInstancePath); UpdateAppConfigs(tempJobInstancePath); _workingDirectory = tempJobInstancePath; }); } catch (Exception ex) { //Status = "Worker is not running due to an error"; //TraceError("Failed to copy bin directory: " + ex); logger.LogError("Failed to copy job files: " + ex); _analytics.UnexpectedException(ex); // job disabled _workingDirectory = null; } }
private void AssertJob(JobBase expectedJob, JobBase actualJob) { Assert.NotNull(actualJob); Assert.Equal(expectedJob.Name, actualJob.Name); Assert.Equal(expectedJob.RunCommand, actualJob.RunCommand); Assert.Equal(expectedJob.JobType, actualJob.JobType); Assert.NotNull(actualJob.Url); Assert.NotNull(actualJob.ExtraInfoUrl); }
public JobStartedReporter(IAnalytics analytics, JobBase job, string trigger, string siteMode, string jobDataPath) { _analytics = analytics; _job = job; _trigger = trigger; _siteMode = siteMode; _jobDataPath = jobDataPath; _timer = new Timer(Report, null, ReportTimeoutInMilliseconds, Timeout.Infinite); }
protected void RunJobInstance(JobBase job, IJobLogger logger, string runId, string trigger, int port = -1) { string scriptFileName = Path.GetFileName(job.ScriptFilePath); string scriptFileFullPath = Path.Combine(WorkingDirectory, job.RunCommand); string workingDirectoryForScript = Path.GetDirectoryName(scriptFileFullPath); logger.LogInformation("Run script '{0}' with script host - '{1}'".FormatCurrentCulture(scriptFileName, job.ScriptHost.GetType().Name)); using (var jobStartedReporter = new JobStartedReporter(_analytics, job, trigger, Settings.GetWebSiteSku(), JobDataPath)) { try { var exe = _externalCommandFactory.BuildCommandExecutable(job.ScriptHost.HostPath, workingDirectoryForScript, IdleTimeout, NullLogger.Instance); _shutdownNotificationFilePath = RefreshShutdownNotificationFilePath(job.Name, job.JobType); // Set environment variable to be able to identify all processes spawned for this job exe.EnvironmentVariables[GetJobEnvironmentKey()] = "true"; exe.EnvironmentVariables[WellKnownEnvironmentVariables.WebJobsRootPath] = WorkingDirectory; exe.EnvironmentVariables[WellKnownEnvironmentVariables.WebJobsName] = job.Name; exe.EnvironmentVariables[WellKnownEnvironmentVariables.WebJobsType] = job.JobType; exe.EnvironmentVariables[WellKnownEnvironmentVariables.WebJobsDataPath] = JobDataPath; exe.EnvironmentVariables[WellKnownEnvironmentVariables.WebJobsRunId] = runId; exe.EnvironmentVariables[WellKnownEnvironmentVariables.WebJobsCommandArguments] = job.CommandArguments; if (port != -1) { exe.EnvironmentVariables[WellKnownEnvironmentVariables.WebJobsPort] = port.ToString(); } if (_shutdownNotificationFilePath != null) { exe.EnvironmentVariables[WellKnownEnvironmentVariables.WebJobsShutdownNotificationFile] = _shutdownNotificationFilePath; } UpdateStatus(logger, "Running"); int exitCode = exe.ExecuteReturnExitCode( TraceFactory.GetTracer(), logger.LogStandardOutput, logger.LogStandardError, job.ScriptHost.ArgumentsFormat, scriptFileName, job.CommandArguments != null ? " " + job.CommandArguments : String.Empty); if (exitCode != 0) { string errorMessage = "Job failed due to exit code " + exitCode; logger.LogError(errorMessage); jobStartedReporter.Error = errorMessage; } else { UpdateStatus(logger, "Success"); } } catch (ThreadAbortException) { // We kill the process when refreshing the job logger.LogInformation("WebJob process was aborted"); UpdateStatus(logger, "Stopped"); } catch (Exception ex) { logger.LogError(ex.ToString()); jobStartedReporter.Error = ex.Message; } } }
protected void InitializeJobInstance(JobBase job, IJobLogger logger) { if (!String.Equals(JobName, job.Name, StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException( "The job runner can only run jobs with the same name it was configured, configured - {0}, trying to run - {1}".FormatInvariant( JobName, job.Name)); } if (!FileSystemHelpers.FileExists(job.ScriptFilePath)) { throw new InvalidOperationException("Missing job script to run - {0}".FormatInvariant(job.ScriptFilePath)); } CacheJobBinaries(job, logger); if (WorkingDirectory == null) { throw new InvalidOperationException("Missing working directory"); } }
private void CacheJobBinaries(JobBase job, IJobLogger logger) { bool isInPlaceDefault = job.ScriptHost.GetType() == typeof(NodeScriptHost); if (JobSettings.GetIsInPlace(isInPlaceDefault)) { _inPlaceWorkingDirectory = JobBinariesPath; SafeKillAllRunningJobInstances(logger); UpdateAppConfigs(WorkingDirectory, _analytics); return; } _inPlaceWorkingDirectory = null; Dictionary<string, FileInfoBase> sourceDirectoryFileMap = GetJobDirectoryFileMap(JobBinariesPath); if (WorkingDirectory != null) { try { var workingDirectoryFileMap = GetJobDirectoryFileMap(WorkingDirectory); if (!JobDirectoryHasChanged(sourceDirectoryFileMap, workingDirectoryFileMap, _cachedSourceDirectoryFileMap, logger)) { // no changes detected, so skip the cache/copy step below return; } } catch (Exception ex) { // Log error and ignore it, since this diff optimization isn't critical. // We'll just do a full copy in this case. logger.LogWarning("Failed to diff WebJob directories for changes. Continuing to copy WebJob binaries (this will not affect the WebJob run)\n" + ex); _analytics.UnexpectedException(ex); } } SafeKillAllRunningJobInstances(logger); if (FileSystemHelpers.DirectoryExists(JobTempPath)) { FileSystemHelpers.DeleteDirectorySafe(JobTempPath, ignoreErrors: true); } if (FileSystemHelpers.DirectoryExists(JobTempPath)) { logger.LogWarning("Failed to delete temporary directory"); } try { OperationManager.Attempt(() => { var tempJobInstancePath = Path.Combine(JobTempPath, Path.GetRandomFileName()); FileSystemHelpers.CopyDirectoryRecursive(JobBinariesPath, tempJobInstancePath); UpdateAppConfigs(tempJobInstancePath, _analytics); _workingDirectory = tempJobInstancePath; // cache the file map snapshot for next time (to aid in detecting // file deletions) _cachedSourceDirectoryFileMap = sourceDirectoryFileMap; }); } catch (Exception ex) { //Status = "Worker is not running due to an error"; //TraceError("Failed to copy bin directory: " + ex); logger.LogError("Failed to copy job files: " + ex); _analytics.UnexpectedException(ex); // job disabled _workingDirectory = null; } }
protected void RunJobInstance(JobBase job, IJobLogger logger, string runId) { string scriptFileName = Path.GetFileName(job.ScriptFilePath); string scriptFileExtension = Path.GetExtension(job.ScriptFilePath); logger.LogInformation("Run script '{0}' with script host - '{1}'".FormatCurrentCulture(scriptFileName, job.ScriptHost.GetType().Name)); string siteMode = Settings.GetWebSitePolicy(); _analytics.JobStarted(job.Name.Fuzz(), scriptFileExtension, job.JobType, siteMode); try { var exe = _externalCommandFactory.BuildCommandExecutable(job.ScriptHost.HostPath, WorkingDirectory, IdleTimeout, NullLogger.Instance); // Set environment variable to be able to identify all processes spawned for this job exe.EnvironmentVariables[GetJobEnvironmentKey()] = "true"; exe.EnvironmentVariables[WellKnownEnvironmentVariables.WebJobsRootPath] = WorkingDirectory; exe.EnvironmentVariables[WellKnownEnvironmentVariables.WebJobsName] = job.Name; exe.EnvironmentVariables[WellKnownEnvironmentVariables.WebJobsType] = job.JobType; exe.EnvironmentVariables[WellKnownEnvironmentVariables.WebJobsDataPath] = JobDataPath; exe.EnvironmentVariables[WellKnownEnvironmentVariables.WebJobsRunId] = runId; exe.EnvironmentVariables[WellKnownEnvironmentVariables.WebJobsExtraUrlPath] = JobsManagerBase.GetJobExtraInfoUrlFilePath(JobDataPath); UpdateStatus(logger, "Running"); int exitCode = exe.ExecuteReturnExitCode( TraceFactory.GetTracer(), logger.LogStandardOutput, logger.LogStandardError, job.ScriptHost.ArgumentsFormat, job.RunCommand); if (exitCode != 0) { logger.LogError("Job failed due to exit code " + exitCode); } else { UpdateStatus(logger, "Success"); } } catch (Exception ex) { if (ex is ThreadAbortException) { // We kill the process when refreshing the job logger.LogInformation("Job aborted"); UpdateStatus(logger, "Aborted"); return; } logger.LogError(ex.ToString()); } }