Piscal processing work
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Configuration;
|
using System.Configuration;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using LeafWeb.Core.Remote;
|
using LeafWeb.Core.Remote;
|
||||||
using LeafWeb.Core.Utility;
|
using LeafWeb.Core.Utility;
|
||||||
@@ -10,17 +11,19 @@ namespace LeafWeb.Core.Tests.Remote
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class PiscalSshClientTests
|
public class PiscalSshClientTests
|
||||||
{
|
{
|
||||||
|
private const string ContentDirectory = @"Parsers\LeafInputData\";
|
||||||
|
|
||||||
private readonly PiscalLeafInput _testInput =
|
private readonly PiscalLeafInput _testInput =
|
||||||
new PiscalLeafInput
|
new PiscalLeafInput
|
||||||
{
|
{
|
||||||
LeafInputId = 1,
|
LeafInputId = 1,
|
||||||
DirectoryName = "TestDirectory2",
|
DirectoryName = "TestDirectory3",
|
||||||
PhotosyntheticType = "C4_photosynthesis_leafweb",
|
PhotosyntheticType = "C4_photosynthesis_leafweb",
|
||||||
InputFiles = new[]
|
InputFiles = new[]
|
||||||
{
|
{
|
||||||
new PiscalLeafInputFile
|
new PiscalLeafInputFile
|
||||||
{
|
{
|
||||||
Filename = "blah", Contents = "test".GetBytes()
|
Filename = "valid.csv", Contents = File.ReadAllBytes(FileUtility.GetContentFile(ContentDirectory, "LeafInput-valid.csv").FullName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -28,17 +31,22 @@ namespace LeafWeb.Core.Tests.Remote
|
|||||||
private readonly string _piscalConnectionString =
|
private readonly string _piscalConnectionString =
|
||||||
ConfigurationManager.ConnectionStrings["PiscalServer"].ConnectionString;
|
ConfigurationManager.ConnectionStrings["PiscalServer"].ConnectionString;
|
||||||
|
|
||||||
|
private PiscalSshClient GetTestClient()
|
||||||
|
{
|
||||||
|
return new PiscalSshClient(_piscalConnectionString);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void SubmitLeafInputFile()
|
public void SubmitLeafInputFile()
|
||||||
{
|
{
|
||||||
var client = new PiscalSshClient(_piscalConnectionString);
|
var client = GetTestClient();
|
||||||
client.RunLeafInput(_testInput);
|
client.RunLeafInput(_testInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void GetLeafInputStatus()
|
public void GetLeafInputStatus()
|
||||||
{
|
{
|
||||||
var client = new PiscalSshClient(_piscalConnectionString);
|
var client = GetTestClient();
|
||||||
var leafInputStatus = client.GetLeafInputStatus(_testInput);
|
var leafInputStatus = client.GetLeafInputStatus(_testInput);
|
||||||
Console.WriteLine(leafInputStatus);
|
Console.WriteLine(leafInputStatus);
|
||||||
}
|
}
|
||||||
@@ -46,10 +54,17 @@ namespace LeafWeb.Core.Tests.Remote
|
|||||||
[Test]
|
[Test]
|
||||||
public void RetrieveLeafOutput()
|
public void RetrieveLeafOutput()
|
||||||
{
|
{
|
||||||
var client = new PiscalSshClient(_piscalConnectionString);
|
var client = GetTestClient();
|
||||||
var result = client.RetrieveLeafOutput(_testInput).ToList();
|
var result = client.RetrieveLeafOutput(_testInput).ToList();
|
||||||
Console.WriteLine(string.Join(", ", result.Select(o => o.Filename)));
|
Console.WriteLine(string.Join(", ", result.Select(o => o.Filename)));
|
||||||
//Console.WriteLine(result[0].Contents.GetString());
|
//Console.WriteLine(result[0].Contents.GetString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CleanLeafOutput()
|
||||||
|
{
|
||||||
|
var client = GetTestClient();
|
||||||
|
client.CleanupLeafProcess(_testInput);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,10 @@
|
|||||||
<HintPath>..\packages\fasterflect.2.1.3\lib\net40\Fasterflect.dll</HintPath>
|
<HintPath>..\packages\fasterflect.2.1.3\lib\net40\Fasterflect.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\NLog.4.2.3\lib\net45\NLog.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="Renci.SshNet, Version=2013.4.7.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Renci.SshNet, Version=2013.4.7.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\SSH.NET.2013.4.7\lib\net40\Renci.SshNet.dll</HintPath>
|
<HintPath>..\packages\SSH.NET.2013.4.7\lib\net40\Renci.SshNet.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
@@ -88,6 +92,7 @@
|
|||||||
<Compile Include="Entities\LeafInputStatus.cs" />
|
<Compile Include="Entities\LeafInputStatus.cs" />
|
||||||
<Compile Include="Parsers\FluxnetSiteCsvParser.cs" />
|
<Compile Include="Parsers\FluxnetSiteCsvParser.cs" />
|
||||||
<Compile Include="Remote\PiscalClientException.cs" />
|
<Compile Include="Remote\PiscalClientException.cs" />
|
||||||
|
<Compile Include="Remote\PiscalLeafInput.cs" />
|
||||||
<Compile Include="Remote\PiscalLeafInputFile.cs" />
|
<Compile Include="Remote\PiscalLeafInputFile.cs" />
|
||||||
<Compile Include="Remote\PiscalLeafOutputFile.cs" />
|
<Compile Include="Remote\PiscalLeafOutputFile.cs" />
|
||||||
<Compile Include="Remote\PiscalSshClient.cs" />
|
<Compile Include="Remote\PiscalSshClient.cs" />
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ namespace LeafWeb.Core.DAL
|
|||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetLeafInputStatusNoUpdate(LeafInput leafInputFile, LeafInputStatusType status, string description = null)
|
private void SetLeafInputStatusNoUpdate(LeafInput leafInputFile, LeafInputStatusType status, string description = null, string details = null)
|
||||||
{
|
{
|
||||||
leafInputFile.CurrentStatus = status;
|
leafInputFile.CurrentStatus = status;
|
||||||
var leafInputFileStatus = new LeafInputStatus
|
var leafInputFileStatus = new LeafInputStatus
|
||||||
@@ -74,6 +74,7 @@ namespace LeafWeb.Core.DAL
|
|||||||
Status = status,
|
Status = status,
|
||||||
DateTime = DateTime.Now,
|
DateTime = DateTime.Now,
|
||||||
Description = description,
|
Description = description,
|
||||||
|
Details = details,
|
||||||
LeafInput = leafInputFile
|
LeafInput = leafInputFile
|
||||||
};
|
};
|
||||||
if (leafInputFile.StatusHistory == null)
|
if (leafInputFile.StatusHistory == null)
|
||||||
@@ -81,9 +82,9 @@ namespace LeafWeb.Core.DAL
|
|||||||
leafInputFile.StatusHistory.Add(leafInputFileStatus);
|
leafInputFile.StatusHistory.Add(leafInputFileStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetLeafInputStatus(LeafInput leafInput, LeafInputStatusType status, string description = null)
|
public void SetLeafInputStatus(LeafInput leafInput, LeafInputStatusType status, string description = null, string details = null)
|
||||||
{
|
{
|
||||||
SetLeafInputStatusNoUpdate(leafInput, status, description);
|
SetLeafInputStatusNoUpdate(leafInput, status, description, details);
|
||||||
UpdateLeafInput(leafInput);
|
UpdateLeafInput(leafInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ namespace LeafWeb.Core.Entities
|
|||||||
public virtual LeafInput LeafInput { get; set; }
|
public virtual LeafInput LeafInput { get; set; }
|
||||||
public LeafInputStatusType Status { get; set; }
|
public LeafInputStatusType Status { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
public string Details { get; set; }
|
||||||
public DateTime DateTime { get; set; }
|
public DateTime DateTime { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,6 @@ namespace LeafWeb.Core.Entities
|
|||||||
Pending = 0,
|
Pending = 0,
|
||||||
Running = 1,
|
Running = 1,
|
||||||
Complete = 2,
|
Complete = 2,
|
||||||
Error = 3
|
Exception = 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,5 @@ namespace LeafWeb.Core.Remote
|
|||||||
PiscalStatus GetLeafInputStatus(PiscalLeafInput leafInput);
|
PiscalStatus GetLeafInputStatus(PiscalLeafInput leafInput);
|
||||||
IEnumerable<PiscalLeafOutputFile> RetrieveLeafOutput(PiscalLeafInput leafInput);
|
IEnumerable<PiscalLeafOutputFile> RetrieveLeafOutput(PiscalLeafInput leafInput);
|
||||||
void CleanupLeafProcess(PiscalLeafInput leafInput);
|
void CleanupLeafProcess(PiscalLeafInput leafInput);
|
||||||
string GetErrorMessage(PiscalLeafInput leafInput);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using AutoMapper;
|
||||||
|
using LeafWeb.Core.Entities;
|
||||||
|
using LeafWeb.Core.Utility;
|
||||||
|
|
||||||
|
namespace LeafWeb.Core.Remote
|
||||||
|
{
|
||||||
|
public class PiscalLeafInput
|
||||||
|
{
|
||||||
|
private static readonly IMapper Mapper;
|
||||||
|
public int LeafInputId { get; set; }
|
||||||
|
public string PhotosyntheticType { get; set; }
|
||||||
|
public string DirectoryName { get; set; }
|
||||||
|
public PiscalLeafInputFile[] InputFiles { get; set; }
|
||||||
|
|
||||||
|
static PiscalLeafInput()
|
||||||
|
{
|
||||||
|
var config =
|
||||||
|
new MapperConfiguration(cfg =>
|
||||||
|
{
|
||||||
|
cfg.CreateMap<LeafInput, PiscalLeafInput>()
|
||||||
|
.ForMember(dest => dest.DirectoryName,
|
||||||
|
opt => opt.MapFrom(src => PiscalUtility.GetPiscalDirectoryName(src)))
|
||||||
|
.ForMember(dest => dest.LeafInputId, opt => opt.MapFrom(src => src.Id))
|
||||||
|
.ForMember(dest => dest.InputFiles, opt => opt.MapFrom(src => src.InputFiles.Select(f => new PiscalLeafInputFile(f)).ToArray()))
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.PhotosyntheticType,
|
||||||
|
opt => opt.MapFrom(src => src.PhotosynthesisType.Id.WhitespaceToUnderscore()));
|
||||||
|
});
|
||||||
|
Mapper = config.CreateMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PiscalLeafInput() { }
|
||||||
|
|
||||||
|
public PiscalLeafInput(LeafInput leafInput)
|
||||||
|
{
|
||||||
|
Mapper.Map(leafInput, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,43 +1,9 @@
|
|||||||
using System.Linq;
|
using AutoMapper;
|
||||||
using AutoMapper;
|
|
||||||
using LeafWeb.Core.Entities;
|
using LeafWeb.Core.Entities;
|
||||||
using LeafWeb.Core.Utility;
|
using LeafWeb.Core.Utility;
|
||||||
|
|
||||||
namespace LeafWeb.Core.Remote
|
namespace LeafWeb.Core.Remote
|
||||||
{
|
{
|
||||||
public class PiscalLeafInput
|
|
||||||
{
|
|
||||||
private static readonly IMapper Mapper;
|
|
||||||
public int LeafInputId { get; set; }
|
|
||||||
public string PhotosyntheticType { get; set; }
|
|
||||||
public string DirectoryName { get; set; }
|
|
||||||
public PiscalLeafInputFile[] InputFiles { get; set; }
|
|
||||||
|
|
||||||
static PiscalLeafInput()
|
|
||||||
{
|
|
||||||
var config =
|
|
||||||
new MapperConfiguration(cfg =>
|
|
||||||
{
|
|
||||||
cfg.CreateMap<LeafInput, PiscalLeafInput>()
|
|
||||||
.ForMember(dest => dest.DirectoryName,
|
|
||||||
opt => opt.MapFrom(src => PiscalUtility.GetPiscalDirectoryName(src)))
|
|
||||||
.ForMember(dest => dest.LeafInputId, opt => opt.MapFrom(src => src.Id))
|
|
||||||
.ForMember(dest => dest.InputFiles, opt => opt.MapFrom(src => src.InputFiles.Select(f => new PiscalLeafInputFile(f)).ToArray()))
|
|
||||||
.ForMember(
|
|
||||||
dest => dest.PhotosyntheticType,
|
|
||||||
opt => opt.MapFrom(src => src.PhotosynthesisType.Id.WhitespaceToUnderscore()));
|
|
||||||
});
|
|
||||||
Mapper = config.CreateMapper();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PiscalLeafInput() { }
|
|
||||||
|
|
||||||
public PiscalLeafInput(LeafInput leafInput)
|
|
||||||
{
|
|
||||||
Mapper.Map(leafInput, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PiscalLeafInputFile
|
public class PiscalLeafInputFile
|
||||||
{
|
{
|
||||||
private static readonly IMapper Mapper;
|
private static readonly IMapper Mapper;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Data.Common;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using LeafWeb.Core.Utility;
|
using LeafWeb.Core.Utility;
|
||||||
|
using NLog;
|
||||||
using Renci.SshNet;
|
using Renci.SshNet;
|
||||||
|
|
||||||
namespace LeafWeb.Core.Remote
|
namespace LeafWeb.Core.Remote
|
||||||
@@ -14,10 +15,11 @@ namespace LeafWeb.Core.Remote
|
|||||||
private const string RemoteScriptPath = BaseDirectory + "/piscal_manager.sh";
|
private const string RemoteScriptPath = BaseDirectory + "/piscal_manager.sh";
|
||||||
private readonly PasswordConnectionInfo _connectionInfo;
|
private readonly PasswordConnectionInfo _connectionInfo;
|
||||||
|
|
||||||
private const string StatusSuccess = "success";
|
private const string StatusComplete = "complete";
|
||||||
private const string StatusRunning = "running";
|
private const string StatusRunning = "running";
|
||||||
private const string StatusNotStarted = "not started";
|
private const string StatusNotStarted = "not started";
|
||||||
private const string StatusError = "error";
|
|
||||||
|
Logger _logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
public PiscalSshClient(string connectionString)
|
public PiscalSshClient(string connectionString)
|
||||||
{
|
{
|
||||||
@@ -45,10 +47,10 @@ namespace LeafWeb.Core.Remote
|
|||||||
using (var scp = GetScpClient())
|
using (var scp = GetScpClient())
|
||||||
foreach (var file in leafInput.InputFiles)
|
foreach (var file in leafInput.InputFiles)
|
||||||
{
|
{
|
||||||
var inputPath = $"{directory}/{file.Filename}";
|
var inputPath = $"{directory}/input/{file.Filename}";
|
||||||
using (var stream = new MemoryStream(file.Contents))
|
using (var stream = new MemoryStream(file.Contents))
|
||||||
{
|
{
|
||||||
Console.WriteLine(inputPath);
|
_logger.Trace("Copying " + inputPath);
|
||||||
scp.Connect();
|
scp.Connect();
|
||||||
scp.Upload(stream, inputPath);
|
scp.Upload(stream, inputPath);
|
||||||
scp.Disconnect();
|
scp.Disconnect();
|
||||||
@@ -66,8 +68,7 @@ namespace LeafWeb.Core.Remote
|
|||||||
using (var ssh = GetSshClient())
|
using (var ssh = GetSshClient())
|
||||||
{
|
{
|
||||||
ssh.Connect();
|
ssh.Connect();
|
||||||
var commandText = $"{RemoteScriptPath} -d {leafInput.DirectoryName} -p {leafInput.PhotosyntheticType}";
|
var commandText = $"{RemoteScriptPath} -d {leafInput.DirectoryName} -p {leafInput.PhotosyntheticType} -s";
|
||||||
Console.Write(commandText);
|
|
||||||
var command = ssh.CreateCommand(commandText);
|
var command = ssh.CreateCommand(commandText);
|
||||||
command.Execute();
|
command.Execute();
|
||||||
ssh.Disconnect();
|
ssh.Disconnect();
|
||||||
@@ -75,7 +76,7 @@ namespace LeafWeb.Core.Remote
|
|||||||
if (command.ExitStatus != 0)
|
if (command.ExitStatus != 0)
|
||||||
throw new PiscalClientException(command.Result);
|
throw new PiscalClientException(command.Result);
|
||||||
|
|
||||||
Console.Write(command.Result);
|
_logger.Debug(command.Result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,12 +88,12 @@ namespace LeafWeb.Core.Remote
|
|||||||
{
|
{
|
||||||
case StatusRunning:
|
case StatusRunning:
|
||||||
return PiscalStatus.Running;
|
return PiscalStatus.Running;
|
||||||
case StatusSuccess:
|
case StatusComplete:
|
||||||
return PiscalStatus.Success;
|
return PiscalStatus.Complete;
|
||||||
case StatusNotStarted:
|
case StatusNotStarted:
|
||||||
return PiscalStatus.NotStarted;
|
return PiscalStatus.NotStarted;
|
||||||
default:
|
default:
|
||||||
return PiscalStatus.Error;
|
throw new PiscalClientException("Unknown status: " + statusRaw[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +102,7 @@ namespace LeafWeb.Core.Remote
|
|||||||
using (var ssh = GetSshClient())
|
using (var ssh = GetSshClient())
|
||||||
{
|
{
|
||||||
ssh.Connect();
|
ssh.Connect();
|
||||||
var commandText = $"{RemoteScriptPath} -d {leafInput.DirectoryName} -s";
|
var commandText = $"{RemoteScriptPath} -d {leafInput.DirectoryName}";
|
||||||
var command = ssh.CreateCommand(commandText);
|
var command = ssh.CreateCommand(commandText);
|
||||||
command.Execute();
|
command.Execute();
|
||||||
ssh.Disconnect();
|
ssh.Disconnect();
|
||||||
@@ -123,7 +124,7 @@ namespace LeafWeb.Core.Remote
|
|||||||
{
|
{
|
||||||
// get output files
|
// get output files
|
||||||
var status = GetLeafInputStatusRaw(leafInput);
|
var status = GetLeafInputStatusRaw(leafInput);
|
||||||
if (status[0] != StatusSuccess)
|
if (status[0] != StatusComplete)
|
||||||
throw new PiscalClientException("output not available, status is " + status[0]);
|
throw new PiscalClientException("output not available, status is " + status[0]);
|
||||||
|
|
||||||
var filePaths = status.Skip(1);
|
var filePaths = status.Skip(1);
|
||||||
@@ -149,23 +150,9 @@ namespace LeafWeb.Core.Remote
|
|||||||
scp.Disconnect();
|
scp.Disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetErrorMessage(PiscalLeafInput leafInput)
|
|
||||||
{
|
|
||||||
var status = GetLeafInputStatusRaw(leafInput);
|
|
||||||
if (status[0] != StatusError)
|
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
var errorLines = status.Skip(1).ToArray();
|
|
||||||
return errorLines.Join(Environment.NewLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CleanupLeafProcess(PiscalLeafInput leafInput)
|
public void CleanupLeafProcess(PiscalLeafInput leafInput)
|
||||||
{
|
{
|
||||||
var status = GetLeafInputStatusRaw(leafInput);
|
|
||||||
if (status[0] == StatusRunning)
|
|
||||||
throw new PiscalClientException("Trying to cleanup a running process");
|
|
||||||
|
|
||||||
using (var ssh = GetSshClient())
|
using (var ssh = GetSshClient())
|
||||||
{
|
{
|
||||||
ssh.Connect();
|
ssh.Connect();
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ namespace LeafWeb.Core.Remote
|
|||||||
{
|
{
|
||||||
public enum PiscalStatus
|
public enum PiscalStatus
|
||||||
{
|
{
|
||||||
Running,
|
NotStarted, // Process has not been started
|
||||||
Success,
|
Running, // Process is currently executing
|
||||||
NotStarted,
|
Complete, // Process has completed
|
||||||
Error
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,5 +4,6 @@
|
|||||||
<package id="CsvHelper" version="2.13.2.0" targetFramework="net45" />
|
<package id="CsvHelper" version="2.13.2.0" targetFramework="net45" />
|
||||||
<package id="EntityFramework" version="6.1.3" targetFramework="net45" />
|
<package id="EntityFramework" version="6.1.3" targetFramework="net45" />
|
||||||
<package id="fasterflect" version="2.1.3" targetFramework="net45" />
|
<package id="fasterflect" version="2.1.3" targetFramework="net45" />
|
||||||
|
<package id="NLog" version="4.2.3" targetFramework="net45" />
|
||||||
<package id="SSH.NET" version="2013.4.7" targetFramework="net45" />
|
<package id="SSH.NET" version="2013.4.7" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
||||||
@@ -61,7 +61,7 @@ namespace LeafWeb.Web.Tests.ViewModels.ResultStatus
|
|||||||
public void CanConstructFromLeafInputFile_Error()
|
public void CanConstructFromLeafInputFile_Error()
|
||||||
{
|
{
|
||||||
var leafInput = GetLeafInput();
|
var leafInput = GetLeafInput();
|
||||||
leafInput.CurrentStatus = LeafInputStatusType.Error;
|
leafInput.CurrentStatus = LeafInputStatusType.Exception;
|
||||||
leafInput.StatusHistory = new []
|
leafInput.StatusHistory = new []
|
||||||
{
|
{
|
||||||
new LeafInputStatus
|
new LeafInputStatus
|
||||||
@@ -69,12 +69,12 @@ namespace LeafWeb.Web.Tests.ViewModels.ResultStatus
|
|||||||
DateTime = DateTime.Today,
|
DateTime = DateTime.Today,
|
||||||
LeafInput = leafInput,
|
LeafInput = leafInput,
|
||||||
Description = "My Error",
|
Description = "My Error",
|
||||||
Status = LeafInputStatusType.Error
|
Status = LeafInputStatusType.Exception
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var viewModel = new ResultStatusViewModel(leafInput);
|
var viewModel = new ResultStatusViewModel(leafInput);
|
||||||
|
|
||||||
Assert.That(viewModel.CurrentStatus, Is.EqualTo(LeafInputStatusType.Error.ToString()));
|
Assert.That(viewModel.CurrentStatus, Is.EqualTo(LeafInputStatusType.Exception.ToString()));
|
||||||
Assert.That(viewModel.ErrorMessages[0], Is.EqualTo(leafInput.StatusHistory.First().Description));
|
Assert.That(viewModel.ErrorMessages[0], Is.EqualTo(leafInput.StatusHistory.First().Description));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
<Compile Include="ViewModels\ResultStatus\ResultStatusViewModelTests.cs" />
|
<Compile Include="ViewModels\ResultStatus\ResultStatusViewModelTests.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<None Include="app.config" />
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<runtime>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
</runtime>
|
||||||
|
</configuration>
|
||||||
@@ -34,17 +34,17 @@ namespace LeafWeb.Web.Services
|
|||||||
public void SendLeafWebError(int leafInputId, string errorMessage)
|
public void SendLeafWebError(int leafInputId, string errorMessage)
|
||||||
{
|
{
|
||||||
var leafInput = _dataService.GetLeafInput(leafInputId);
|
var leafInput = _dataService.GetLeafInput(leafInputId);
|
||||||
var body = $"Your LeafWeb analysis job, {leafInput.Identifier}, encountered the following errors." + Environment.NewLine
|
var body = $"Your leaf analysis job, {leafInput.Identifier}, encountered the following errors." + Environment.NewLine
|
||||||
+ "You will need to correct your input and resubmit." + Environment.NewLine + Environment.NewLine
|
+ "You will need to correct your input and resubmit." + Environment.NewLine + Environment.NewLine
|
||||||
+ errorMessage;
|
+ errorMessage;
|
||||||
var message = new MailMessage(_emaialFromAddress, leafInput.Email, "LeafWeb processing error", body);
|
var message = new MailMessage(_emaialFromAddress, leafInput.Email, "LeafWeb processing error", body);
|
||||||
SendMessage(message);
|
SendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendLeafWebSuccess(int leafInputId)
|
public void SendLeafWebComplete(int leafInputId)
|
||||||
{
|
{
|
||||||
var leafInput = _dataService.GetLeafInput(leafInputId);
|
var leafInput = _dataService.GetLeafInput(leafInputId);
|
||||||
var body = $"Your LeafWeb analysis job, {leafInput.Identifier}, has completed." + Environment.NewLine;
|
var body = $"Your leaf analysis job, {leafInput.Identifier}, has completed." + Environment.NewLine;
|
||||||
var message = new MailMessage(_emaialFromAddress, leafInput.Email, "LeafWeb results", body);
|
var message = new MailMessage(_emaialFromAddress, leafInput.Email, "LeafWeb results", body);
|
||||||
|
|
||||||
var fileStreams =
|
var fileStreams =
|
||||||
|
|||||||
@@ -76,9 +76,11 @@ namespace LeafWeb.Web.Services
|
|||||||
catch (PiscalClientException ex)
|
catch (PiscalClientException ex)
|
||||||
{
|
{
|
||||||
logger.Error("LeafInputFile: {0}, ProcessQueue Exception: {1}", pending.Id, ex.Message);
|
logger.Error("LeafInputFile: {0}, ProcessQueue Exception: {1}", pending.Id, ex.Message);
|
||||||
_dataService.SetLeafInputStatus(pending, LeafInputStatusType.Error, "Error occurred submitting LeafInput");
|
_dataService.SetLeafInputStatus(pending, LeafInputStatusType.Exception, "Error occurred starting LeafInput", ex.Message);
|
||||||
|
logger.Info("LeafInputFile: {0}, Cleanup", pending.Id);
|
||||||
|
_piscalService.Cleanup(pending);
|
||||||
|
|
||||||
// TODO: re-queue
|
// TODO: re-queue?
|
||||||
//_dataService.SetLeafInputFileStatus(queuedFile, LeafInputStatusType.Queued, "Re-queuing LeafInput");
|
//_dataService.SetLeafInputFileStatus(queuedFile, LeafInputStatusType.Queued, "Re-queuing LeafInput");
|
||||||
}
|
}
|
||||||
_dataService.SetLeafInputStatus(pending, LeafInputStatusType.Running);
|
_dataService.SetLeafInputStatus(pending, LeafInputStatusType.Running);
|
||||||
@@ -87,66 +89,54 @@ namespace LeafWeb.Web.Services
|
|||||||
private void ProcessRunning(ILogger logger)
|
private void ProcessRunning(ILogger logger)
|
||||||
{
|
{
|
||||||
var running = _dataService.GetLeafInputs(LeafInputStatusType.Running).ToList();
|
var running = _dataService.GetLeafInputs(LeafInputStatusType.Running).ToList();
|
||||||
foreach (var file in running)
|
foreach (var leafInput in running)
|
||||||
{
|
{
|
||||||
var status = _piscalService.GetStatus(file);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var status = _piscalService.GetStatus(leafInput);
|
||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
|
case PiscalStatus.NotStarted:
|
||||||
|
logger.Warn("LeafInputFile: {0}, Not Started, re-queueing", leafInput.Id);
|
||||||
|
// if it's not started, try to requeue the process - unusual state
|
||||||
|
_dataService.SetLeafInputStatus(leafInput, LeafInputStatusType.Pending);
|
||||||
|
break;
|
||||||
|
|
||||||
case PiscalStatus.Running:
|
case PiscalStatus.Running:
|
||||||
logger.Trace("LeafInputFile: {0}, Running", file.Id);
|
logger.Trace("LeafInputFile: {0}, Running", leafInput.Id);
|
||||||
// continue running
|
// continue running
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PiscalStatus.Success:
|
case PiscalStatus.Complete:
|
||||||
logger.Info("LeafInputFile: {0}, Success", file.Id);
|
logger.Info("LeafInputFile: {0}, Complete", leafInput.Id);
|
||||||
// collect the leaf output
|
// collect the leaf output
|
||||||
var leafOutputFiles = _piscalService.RetrieveOutputFiles(file).ToList();
|
var leafOutputFiles = _piscalService.RetrieveOutputFiles(leafInput).ToList();
|
||||||
foreach (var outputFile in leafOutputFiles)
|
foreach (var outputFile in leafOutputFiles)
|
||||||
_dataService.AddLeafOutputFile(outputFile);
|
_dataService.AddLeafOutputFile(outputFile);
|
||||||
|
|
||||||
logger.Info("LeafInputFile: {0}, output files: {1}", file.Id,
|
logger.Info("LeafInputFile: {0}, output files: {1}", leafInput.Id,
|
||||||
string.Join(", ", leafOutputFiles.Select(o => o.Filename)));
|
string.Join(", ", leafOutputFiles.Select(o => o.Filename)));
|
||||||
|
|
||||||
// update db
|
// update db
|
||||||
_dataService.SetLeafInputStatus(file, LeafInputStatusType.Complete);
|
_dataService.SetLeafInputStatus(leafInput, LeafInputStatusType.Complete);
|
||||||
|
|
||||||
BackgroundJob.Enqueue(() => _emailService.SendLeafWebSuccess(file.Id));
|
BackgroundJob.Enqueue(() => _emailService.SendLeafWebComplete(leafInput.Id));
|
||||||
|
|
||||||
// remove working data from the server
|
// remove working data from the server
|
||||||
logger.Info("LeafInputFile: {0}, Cleanup", file.Id);
|
logger.Info("LeafInputFile: {0}, Cleanup", leafInput.Id);
|
||||||
_piscalService.Cleanup(file);
|
_piscalService.Cleanup(leafInput);
|
||||||
break;
|
|
||||||
|
|
||||||
case PiscalStatus.NotStarted:
|
|
||||||
logger.Warn("LeafInputFile: {0}, Not Started, re-queueing", file.Id);
|
|
||||||
// if it's not started, try to requeue the process - unusual state
|
|
||||||
_dataService.SetLeafInputStatus(file, LeafInputStatusType.Pending);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PiscalStatus.Error:
|
|
||||||
logger.Info("LeafInputFile: {0}, Error", file.Id);
|
|
||||||
|
|
||||||
var errorMessage = _piscalService.GetErrorMessage(file);
|
|
||||||
logger.Info("LeafInputFile: {0}, Error Message: {1}", file.Id, errorMessage);
|
|
||||||
|
|
||||||
_dataService.SetLeafInputStatus(file, LeafInputStatusType.Error, errorMessage);
|
|
||||||
|
|
||||||
BackgroundJob.Enqueue(() => _emailService.SendLeafWebError(file.Id, errorMessage));
|
|
||||||
|
|
||||||
// remove working data from the server
|
|
||||||
logger.Info("LeafInputFile: {0}, Cleanup", file.Id);
|
|
||||||
_piscalService.Cleanup(file);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (PiscalClientException ex)
|
catch (PiscalClientException ex)
|
||||||
{
|
{
|
||||||
logger.Error("LeafInputFile: {0}, ProcessRunning Exception: {1}", file.Id, ex.Message);
|
logger.Error("LeafInputFile: {0}, ProcessRunning Exception: {1}", leafInput.Id, ex.Message);
|
||||||
_dataService.SetLeafInputStatus(file, LeafInputStatusType.Error, "Error occurred processing LeafInput");
|
_dataService.SetLeafInputStatus(leafInput, LeafInputStatusType.Exception, "Error occurred processing LeafInput", ex.Message);
|
||||||
|
|
||||||
// TODO: re-queue
|
// TODO: Send email
|
||||||
|
logger.Info("LeafInputFile: {0}, Cleanup", leafInput.Id);
|
||||||
|
_piscalService.Cleanup(leafInput);
|
||||||
|
// TODO: re-queue ?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,13 +41,7 @@ namespace LeafWeb.Web.Services
|
|||||||
yield return leafOutputFile;
|
yield return leafOutputFile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetErrorMessage(LeafInput leafInput)
|
|
||||||
{
|
|
||||||
var inputFile = new PiscalLeafInput(leafInput);
|
|
||||||
return _piscalClient.GetErrorMessage(inputFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Cleanup(LeafInput leafInput)
|
public void Cleanup(LeafInput leafInput)
|
||||||
{
|
{
|
||||||
var input = new PiscalLeafInput(leafInput);
|
var input = new PiscalLeafInput(leafInput);
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace LeafWeb.Web.ViewModels.ResultStatus
|
|||||||
opt => opt.ResolveUsing(
|
opt => opt.ResolveUsing(
|
||||||
src =>
|
src =>
|
||||||
src.StatusHistory?
|
src.StatusHistory?
|
||||||
.Where(sh => sh.Status == LeafInputStatusType.Error)
|
.Where(sh => sh.Status == LeafInputStatusType.Exception)
|
||||||
.Select(sh => sh.Description)
|
.Select(sh => sh.Description)
|
||||||
.ToArray()
|
.ToArray()
|
||||||
?? new string[] {}));
|
?? new string[] {}));
|
||||||
|
|||||||
Reference in New Issue
Block a user