public BuilderContext(string buildPath, string buildProfile, FileVersionTracker inputHashes, BuildParameterCollection parameters, int maxParallelProcess, string slaveBuilderPath) { BuildPath = buildPath; BuildProfile = buildProfile; InputHashes = inputHashes; Parameters = parameters; SlaveBuilderPath = slaveBuilderPath; MaxParallelProcesses = maxParallelProcess; }
private BuildResultCode BuildSlave() { // Mount build path ((FileSystemProvider)VirtualFileSystem.ApplicationData).ChangeBasePath(builderOptions.BuildDirectory); PrepareDatabases(); VirtualFileSystem.CreateDirectory(VirtualFileSystem.ApplicationDatabasePath); // Open WCF channel with master builder var namedPipeBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None) { SendTimeout = TimeSpan.FromSeconds(300.0) }; var processBuilderRemote = ChannelFactory <IProcessBuilderRemote> .CreateChannel(namedPipeBinding, new EndpointAddress(builderOptions.SlavePipe)); try { RegisterRemoteLogger(processBuilderRemote); // Create scheduler var scheduler = new Scheduler(); var status = ResultStatus.NotProcessed; // Schedule command string buildPath = builderOptions.BuildDirectory; string buildProfile = builderOptions.BuildProfile; Builder.SetupBuildPath(buildPath, VirtualFileSystem.ApplicationDatabaseIndexName); var logger = builderOptions.Logger; MicroThread microthread = scheduler.Add(async() => { // Deserialize command and parameters Command command = processBuilderRemote.GetCommandToExecute(); BuildParameterCollection parameters = processBuilderRemote.GetBuildParameters(); // Run command var inputHashes = FileVersionTracker.GetDefault(); var builderContext = new BuilderContext(buildPath, buildProfile, inputHashes, parameters, 0, null); var commandContext = new RemoteCommandContext(processBuilderRemote, command, builderContext, logger); IndexFileCommand.MountDatabase(commandContext.GetOutputObjectsGroups()); command.PreCommand(commandContext); status = await command.DoCommand(commandContext); command.PostCommand(commandContext, status); // Returns result to master builder processBuilderRemote.RegisterResult(commandContext.ResultEntry); }); while (true) { scheduler.Run(); // Exit loop if no more micro threads lock (scheduler.MicroThreads) { if (!scheduler.MicroThreads.Any()) { break; } } Thread.Sleep(0); } // Rethrow any exception that happened in microthread if (microthread.Exception != null) { builderOptions.Logger.Fatal(microthread.Exception.ToString()); return(BuildResultCode.BuildError); } if (status == ResultStatus.Successful || status == ResultStatus.NotTriggeredWasSuccessful) { return(BuildResultCode.Successful); } return(BuildResultCode.BuildError); } finally { // Close WCF channel // ReSharper disable SuspiciousTypeConversion.Global ((IClientChannel)processBuilderRemote).Close(); // ReSharper restore SuspiciousTypeConversion.Global } }
public static BuildResultCode BuildSlave(BuilderOptions options) { // Mount build path ((FileSystemProvider)VirtualFileSystem.ApplicationData).ChangeBasePath(options.BuildDirectory); PrepareDatabases(options); try { VirtualFileSystem.CreateDirectory("/data/"); VirtualFileSystem.CreateDirectory("/data/db/"); } catch (Exception) { throw new OptionException("Invalid Build database path", "database"); } // Open WCF channel with master builder var namedPipeBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None) { SendTimeout = TimeSpan.FromSeconds(300.0) }; var processBuilderRemote = ChannelFactory <IProcessBuilderRemote> .CreateChannel(namedPipeBinding, new EndpointAddress(options.SlavePipe)); try { RegisterRemoteLogger(processBuilderRemote); // Create scheduler var scheduler = new Scheduler(); var status = ResultStatus.NotProcessed; // Schedule command string buildPath = options.BuildDirectory; Logger logger = options.Logger; MicroThread microthread = scheduler.Add(async() => { // Deserialize command and parameters Command command = processBuilderRemote.GetCommandToExecute(); BuildParameterCollection parameters = processBuilderRemote.GetBuildParameters(); // Run command var inputHashes = new DictionaryStore <InputVersionKey, ObjectId>(VirtualFileSystem.OpenStream("/data/db/InputHashes", VirtualFileMode.OpenOrCreate, VirtualFileAccess.ReadWrite, VirtualFileShare.ReadWrite)); var builderContext = new BuilderContext(buildPath, inputHashes, parameters, 0, null); var commandContext = new RemoteCommandContext(processBuilderRemote, command, builderContext, logger); command.PreCommand(commandContext); status = await command.DoCommand(commandContext); command.PostCommand(commandContext, status); // Returns result to master builder processBuilderRemote.RegisterResult(commandContext.ResultEntry); }); while (true) { scheduler.Run(); // Exit loop if no more micro threads lock (scheduler.MicroThreads) { if (!scheduler.MicroThreads.Any()) { break; } } Thread.Sleep(0); } // Rethrow any exception that happened in microthread if (microthread.Exception != null) { options.Logger.Fatal(microthread.Exception.ToString()); return(BuildResultCode.BuildError); } if (status == ResultStatus.Successful || status == ResultStatus.NotTriggeredWasSuccessful) { return(BuildResultCode.Successful); } return(BuildResultCode.BuildError); } finally { // Close WCF channel // ReSharper disable SuspiciousTypeConversion.Global ((IClientChannel)processBuilderRemote).Close(); // ReSharper restore SuspiciousTypeConversion.Global } }
protected CommandContextBase(Command command, BuilderContext builderContext) { CurrentCommand = command; BuildParameters = builderContext.Parameters; ResultEntry = new CommandResultEntry(); }
public ProcessBuilderRemote(LocalCommandContext commandContext, Command remoteCommand, BuildParameterCollection buildParameters) { this.commandContext = commandContext; this.remoteCommand = remoteCommand; this.buildParameters = buildParameters; }
/// <summary> /// Runs this instance. /// </summary> public BuildResultCode Run(Mode mode, bool writeIndexFile = true, bool enableMonitor = true) { // When we setup the database ourself we have to take responsibility to close it after var shouldCloseDatabase = IndexFileCommand.ObjectDatabase == null; SetupBuildPath(buildPath, indexName); PreRun(); runMode = mode; if (IsRunning) throw new InvalidOperationException("An instance of this Builder is already running."); // reset build cache from previous build run var parameters = new BuildParameterCollection(); cancellationTokenSource = new CancellationTokenSource(); Cancelled = false; IsRunning = true; DisableCompressionIds.Clear(); // Reseting result map var inputHashes = FileVersionTracker.GetDefault(); { var builderContext = new BuilderContext(buildPath, buildProfile, inputHashes, parameters, MaxParallelProcesses, SlaveBuilderPath); resultMap = IndexFileCommand.ObjectDatabase; scheduler = new Scheduler(); if (enableMonitor) { threadMonitors.Add(new BuildThreadMonitor(scheduler, BuilderId)); foreach (var monitorPipeName in MonitorPipeNames) threadMonitors.Add(new BuildThreadMonitor(scheduler, BuilderId, monitorPipeName)); foreach (var threadMonitor in threadMonitors) threadMonitor.Start(); } // Schedule the build ScheduleBuildStep(builderContext, null, Root, InitialVariables); // Create threads var threads = Enumerable.Range(0, ThreadCount).Select(x => new Thread(SafeAction.Wrap(RunUntilEnd)) { IsBackground = true }).ToArray(); // Start threads int threadId = 0; foreach (var thread in threads) { thread.Name = (BuilderName ?? "Builder") + " worker thread " + (++threadId); thread.Start(); } // Wait for all threads to finish foreach (var thread in threads) { thread.Join(); } foreach (var threadMonitor in threadMonitors) threadMonitor.Finish(); foreach (var threadMonitor in threadMonitors) threadMonitor.Join(); } threadMonitors.Clear(); BuildResultCode result; if (runMode == Mode.Build) { if (cancellationTokenSource.IsCancellationRequested) { Logger.Error("Build cancelled."); result = BuildResultCode.Cancelled; } else if (stepCounter.Get(ResultStatus.Failed) > 0 || stepCounter.Get(ResultStatus.NotTriggeredPrerequisiteFailed) > 0) { Logger.Error("Build finished in {0} steps. Command results: {1} succeeded, {2} up-to-date, {3} failed, {4} not triggered due to previous failure.", stepCounter.Total, stepCounter.Get(ResultStatus.Successful), stepCounter.Get(ResultStatus.NotTriggeredWasSuccessful), stepCounter.Get(ResultStatus.Failed), stepCounter.Get(ResultStatus.NotTriggeredPrerequisiteFailed)); Logger.Error("Build failed."); result = BuildResultCode.BuildError; } else { Logger.Info("Build finished in {0} steps. Command results: {1} succeeded, {2} up-to-date, {3} failed, {4} not triggered due to previous failure.", stepCounter.Total, stepCounter.Get(ResultStatus.Successful), stepCounter.Get(ResultStatus.NotTriggeredWasSuccessful), stepCounter.Get(ResultStatus.Failed), stepCounter.Get(ResultStatus.NotTriggeredPrerequisiteFailed)); Logger.Info("Build is successful."); result = BuildResultCode.Successful; } } else { string modeName; switch (runMode) { case Mode.Clean: modeName = "Clean"; break; case Mode.CleanAndDelete: modeName = "Clean-and-delete"; break; default: throw new InvalidOperationException("Builder executed in unknown mode."); } if (cancellationTokenSource.IsCancellationRequested) { Logger.Error(modeName + " has been cancelled."); result = BuildResultCode.Cancelled; } else if (stepCounter.Get(ResultStatus.Failed) > 0 || stepCounter.Get(ResultStatus.NotTriggeredPrerequisiteFailed) > 0) { Logger.Error(modeName + " has failed."); result = BuildResultCode.BuildError; } else { Logger.Error(modeName + " has been successfully completed."); result = BuildResultCode.Successful; } } scheduler = null; resultMap = null; IsRunning = false; if (shouldCloseDatabase && IndexFileCommand.ObjectDatabase != null) { IndexFileCommand.ObjectDatabase.Dispose(); IndexFileCommand.ObjectDatabase = null; } return result; }