public async Task <IActionResult> PostAsync([FromBody] AILabelingInfo info) { string tempPath, tempDir; tempPath = Path.GetTempPath(); // Remove Base64 header that might be added by the fronted creating the Base64 code info.data.ForEach((x) => x.Base64 = x.Base64.Replace("data:image/png;base64,", "")); tempDir = PathHelper.GetRandomFileNameSecure(tempPath); var(inDir, outDir) = CreateFolders(tempDir); info.data.ForEach((x) => { var bytes = x.Base64.Base64ToByte(); System.IO.File.WriteAllBytes(Path.Combine(inDir, x.Name), bytes); }); // Combine options List <string> options; options = new List <string>(); options.Add("--rm"); options.Add(info.config.Options); options.Add($"-v {inDir}:{info.config.InputDirectory}"); options.Add($"-v {outDir}:{info.config.OutputDirectory}"); var optionsString = string.Join(" ", options.ToArray()); var res = await Docker.RunAsync(info.config.DockerImageName, optionsString, info.config.Parameter); IActionResult actionResult; try { var filePaths = Directory.GetFiles(outDir); var projectId = info.data.First().ProjectId; var files = filePaths.Select(path => EncodeImage(projectId, path)); actionResult = Ok(await Task.WhenAll(files)); } catch (Exception e) { actionResult = BadRequest(e.Message); } // Delete temporaryDirectory and return Directory.Delete(tempDir, true); return(actionResult); }
private Task LaunchService(Application application, Service service) { var serviceDescription = service.Description; if (serviceDescription.DockerImage != null) { return(Docker.RunAsync(_logger, service)); } var serviceName = serviceDescription.Name; var path = ""; var workingDirectory = ""; var args = service.Description.Args ?? ""; if (serviceDescription.Project != null) { var fullProjectPath = Path.GetFullPath(Path.Combine(application.ContextDirectory, serviceDescription.Project)); path = GetExePath(fullProjectPath); workingDirectory = Path.GetDirectoryName(fullProjectPath); service.Status["projectFilePath"] = fullProjectPath; } else { path = Path.GetFullPath(Path.Combine(application.ContextDirectory, serviceDescription.Executable)); workingDirectory = serviceDescription.WorkingDirectory != null? Path.GetFullPath(Path.Combine(application.ContextDirectory, serviceDescription.WorkingDirectory)) : Path.GetDirectoryName(path); // If this is a dll then use dotnet to run it if (Path.GetExtension(path) == ".dll") { args = $"\"{path}\" {args}".Trim(); path = "dotnet"; } } service.Status["executablePath"] = path; service.Status["workingDirectory"] = workingDirectory; service.Status["args"] = args; service.Status["debugMode"] = _debugMode; var processInfo = new ProcessInfo { Threads = new Thread[service.Description.Replicas.Value] }; void RunApplication(IEnumerable <(int Port, string Protocol)> ports) { var hasPorts = ports.Any(); var restarts = 0; var environment = new Dictionary <string, string> { // Default to development environment ["DOTNET_ENVIRONMENT"] = "Development" }; application.PopulateEnvironment(service, (k, v) => environment[k] = v); if (_debugMode) { environment["DOTNET_STARTUP_HOOKS"] = typeof(Hosting.Runtime.HostingRuntimeHelpers).Assembly.Location; } if (hasPorts) { // These ports should also be passed in not assuming ASP.NET Core environment["ASPNETCORE_URLS"] = string.Join(";", ports.Select(p => $"{p.Protocol ?? "http"}://localhost:{p.Port}")); } while (!processInfo.StoppedTokenSource.IsCancellationRequested) { var replica = serviceName + "_" + Guid.NewGuid().ToString().Substring(0, 10).ToLower(); var status = service.Replicas[replica] = new ServiceReplica(); // This isn't your host name environment["APP_INSTANCE"] = replica; status["exitCode"] = null; status["pid"] = null; status["env"] = environment; if (hasPorts) { status["ports"] = ports; } service.Status["restarts"] = restarts; _logger.LogInformation("Launching service {ServiceName} from {ExePath} {args}", replica, path, args); var metricsTokenSource = CancellationTokenSource.CreateLinkedTokenSource(processInfo.StoppedTokenSource.Token); var metricsThread = new Thread(state => CollectMetrics((int)state, replica, status, metricsTokenSource.Token)); try { var result = ProcessUtil.Run(path, args, environmentVariables: environment, workingDirectory: workingDirectory, outputDataReceived: data => { if (data == null) { return; } service.Logs.Add("[" + replica + "]: " + data); }, onStart: pid => { if (hasPorts) { _logger.LogInformation("{ServiceName} running on process id {PID} bound to {Address}", replica, pid, string.Join(", ", ports.Select(p => $"{p.Protocol ?? "http"}://localhost:{p.Port}"))); } else { _logger.LogInformation("{ServiceName} running on process id {PID}", replica, pid); } status["pid"] = pid; metricsThread.Start(pid); }, throwOnError: false, cancellationToken: processInfo.StoppedTokenSource.Token); status["exitCode"] = result.ExitCode; if (status["pid"] != null) { metricsTokenSource.Cancel(); metricsThread.Join(); } } catch (Exception ex) { _logger.LogError(0, ex, "Failed to launch process for service {ServiceName}", replica); Thread.Sleep(5000); } restarts++; if (status["exitCode"] != null) { _logger.LogInformation("{ServiceName} process exited with exit code {ExitCode}", replica, status["exitCode"]); } // Remove the replica from the set service.Replicas.TryRemove(replica, out _); } } if (serviceDescription.Bindings.Count > 0) { // Each replica is assigned a list of internal ports, one mapped to each external // port for (int i = 0; i < serviceDescription.Replicas; i++) { var ports = new List <(int, string)>(); foreach (var binding in serviceDescription.Bindings) { if (binding.Port == null) { continue; } ports.Add((service.PortMap[binding.Port.Value][i], binding.Protocol)); } processInfo.Threads[i] = new Thread(() => RunApplication(ports)); } } else { for (int i = 0; i < service.Description.Replicas; i++) { processInfo.Threads[i] = new Thread(() => RunApplication(Enumerable.Empty <(int, string)>())); } } for (int i = 0; i < service.Description.Replicas; i++) { processInfo.Threads[i].Start(); } service.Items[typeof(ProcessInfo)] = processInfo; return(Task.CompletedTask); }
private Task LaunchService(Application application, Service service) { var serviceDescription = service.Description; if (serviceDescription.DockerImage != null) { return(Docker.RunAsync(_logger, service)); } var serviceName = serviceDescription.Name; var path = ""; var workingDirectory = ""; var args = service.Description.Args ?? ""; var applicationName = ""; if (serviceDescription.Project != null) { var fullProjectPath = Path.GetFullPath(Path.Combine(application.ContextDirectory, serviceDescription.Project)); path = GetExePath(fullProjectPath); workingDirectory = Path.GetDirectoryName(fullProjectPath); // TODO: Requires msbuild applicationName = Path.GetFileNameWithoutExtension(fullProjectPath); service.Status.ProjectFilePath = fullProjectPath; } else { applicationName = Path.GetFileNameWithoutExtension(serviceDescription.Executable); path = Path.GetFullPath(Path.Combine(application.ContextDirectory, serviceDescription.Executable)); workingDirectory = serviceDescription.WorkingDirectory != null? Path.GetFullPath(Path.Combine(application.ContextDirectory, serviceDescription.WorkingDirectory)) : Path.GetDirectoryName(path); } // If this is a dll then use dotnet to run it if (Path.GetExtension(path) == ".dll") { applicationName = Path.GetFileNameWithoutExtension(path); args = $"\"{path}\" {args}".Trim(); path = "dotnet"; } service.Status.ExecutablePath = path; service.Status.WorkingDirectory = workingDirectory; service.Status.Args = args; var processInfo = new ProcessInfo { Threads = new Thread[service.Description.Replicas.Value] }; if (service.Status.ProjectFilePath != null && service.Description.Build && _buildProjects) { _logger.LogInformation("Building project {ProjectFile}", service.Status.ProjectFilePath); service.Logs.OnNext("======================BUILDING===================="); var buildResult = ProcessUtil.Run("dotnet", $"build \"{service.Status.ProjectFilePath}\" /nologo", outputDataReceived: data => service.Logs.OnNext(data), throwOnError: false); service.Logs.OnNext(""); if (buildResult.ExitCode != 0) { _logger.LogInformation("Building {ProjectFile} failed with exit code {ExitCode}: " + buildResult.StandardError, service.Status.ProjectFilePath, buildResult.ExitCode); return(Task.CompletedTask); } } void RunApplication(IEnumerable <(int Port, int BindingPort, string Protocol)> ports) { var hasPorts = ports.Any(); var environment = new Dictionary <string, string> { // Default to development environment ["DOTNET_ENVIRONMENT"] = "Development" }; application.PopulateEnvironment(service, (k, v) => environment[k] = v); if (_debugMode) { environment["DOTNET_STARTUP_HOOKS"] = typeof(Hosting.Runtime.HostingRuntimeHelpers).Assembly.Location; } if (hasPorts) { // These ports should also be passed in not assuming ASP.NET Core environment["ASPNETCORE_URLS"] = string.Join(";", ports.Select(p => $"{p.Protocol ?? "http"}://localhost:{p.Port}")); foreach (var p in ports) { environment[$"{p.Protocol?.ToUpper() ?? "HTTP"}_PORT"] = p.BindingPort.ToString(); } } while (!processInfo.StoppedTokenSource.IsCancellationRequested) { var replica = serviceName + "_" + Guid.NewGuid().ToString().Substring(0, 10).ToLower(); var status = new ProcessStatus(); service.Replicas[replica] = status; // This isn't your host name environment["APP_INSTANCE"] = replica; status.ExitCode = null; status.Pid = null; status.Environment = environment; if (hasPorts) { status.Ports = ports.Select(p => p.Port); } _logger.LogInformation("Launching service {ServiceName}: {ExePath} {args}", replica, path, args); var metricsTokenSource = CancellationTokenSource.CreateLinkedTokenSource(processInfo.StoppedTokenSource.Token); // This is the thread that will collect diagnostics from the running process // - Logs - I'll collect structured logs from Microsoft.Extensions.Logging // - Metrics - It'll collect EventCounters // - Distribued Traces - It'll create spans var diagnosticsThread = new Thread(state => { _diagnosticsCollector.ProcessEvents( applicationName, service.Description.Name, (int)state, replica, status, metricsTokenSource.Token); }); try { var result = ProcessUtil.Run(path, args, environmentVariables: environment, workingDirectory: workingDirectory, outputDataReceived: data => service.Logs.OnNext("[" + replica + "]: " + data), onStart: pid => { if (hasPorts) { _logger.LogInformation("{ServiceName} running on process id {PID} bound to {Address}", replica, pid, string.Join(", ", ports.Select(p => $"{p.Protocol ?? "http"}://localhost:{p.Port}"))); } else { _logger.LogInformation("{ServiceName} running on process id {PID}", replica, pid); } status.Pid = pid; diagnosticsThread.Start(pid); }, throwOnError: false, cancellationToken: processInfo.StoppedTokenSource.Token); status.ExitCode = result.ExitCode; if (status.Pid != null) { metricsTokenSource.Cancel(); diagnosticsThread.Join(); } } catch (Exception ex) { _logger.LogError(0, ex, "Failed to launch process for service {ServiceName}", replica); Thread.Sleep(5000); } service.Restarts++; if (status.ExitCode != null) { _logger.LogInformation("{ServiceName} process exited with exit code {ExitCode}", replica, status.ExitCode); } // Remove the replica from the set service.Replicas.TryRemove(replica, out _); } } if (serviceDescription.Bindings.Count > 0) { // Each replica is assigned a list of internal ports, one mapped to each external // port for (int i = 0; i < serviceDescription.Replicas; i++) { var ports = new List <(int, int, string)>(); foreach (var binding in serviceDescription.Bindings) { if (binding.Port == null) { continue; } ports.Add((service.PortMap[binding.Port.Value][i], binding.Port.Value, binding.Protocol)); } processInfo.Threads[i] = new Thread(() => RunApplication(ports)); } } else { for (int i = 0; i < service.Description.Replicas; i++) { processInfo.Threads[i] = new Thread(() => RunApplication(Enumerable.Empty <(int, int, string)>())); } } for (int i = 0; i < service.Description.Replicas; i++) { processInfo.Threads[i].Start(); } service.Items[typeof(ProcessInfo)] = processInfo; return(Task.CompletedTask); }