|
@@ -1,72 +1,157 @@
|
|
|
-using Quadarax.Foundation.Core.Data;
|
|
|
|
|
|
|
+using qdr.fnd.core.pqueue.Enums;
|
|
|
|
|
+using qdr.fnd.core.pqueue.Exceptions;
|
|
|
|
|
+using Quadarax.Foundation.Core.Data;
|
|
|
using Quadarax.Foundation.Core.Logging;
|
|
using Quadarax.Foundation.Core.Logging;
|
|
|
using Quadarax.Foundation.Core.Object;
|
|
using Quadarax.Foundation.Core.Object;
|
|
|
|
|
+using Quadarax.Foundation.Core.Thread.Extensions;
|
|
|
|
|
+using Quadarax.Foundation.Core.Value.Extensions;
|
|
|
|
|
|
|
|
namespace qdr.fnd.core.pqueue.Process
|
|
namespace qdr.fnd.core.pqueue.Process
|
|
|
{
|
|
{
|
|
|
- public class PsProcessProviderBase : DisposableObject
|
|
|
|
|
|
|
+ public delegate void ProcessDoneCallback(string itemId, PsStatusEnum newStatus, string message);
|
|
|
|
|
+ public delegate void ProcessStdOutputCallback(string itemId, string message);
|
|
|
|
|
+
|
|
|
|
|
+ public abstract class PsProcessProviderBase : DisposableObject, IPsProcessProvider
|
|
|
{
|
|
{
|
|
|
- protected ILog Log { get; private set; }
|
|
|
|
|
|
|
|
|
|
|
|
+ #region *** Constants ***
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// (Output) Argument name for the result code. Type is <see cref="long"/>
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public const string CS_ARG_RESULT_CODE = "result-code";
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// (Output) Argument name for the result test. Type is <see cref="string"/>
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public const string CS_ARG_RESULT_TEXT = "result-text";
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// (Input) Argument name for process timeout. Type is <see cref="TimeSpan"/>
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public const string CS_ARG_PROCESS_TIMEOUT = "process-timeout";
|
|
|
|
|
+ #endregion
|
|
|
|
|
+
|
|
|
|
|
+ #region *** Properties ***
|
|
|
|
|
+ protected ILog Log { get; private set; }
|
|
|
|
|
+ protected ProcessDoneCallback ProcessDoneCallback { get; private set; }
|
|
|
|
|
+ protected ProcessStdOutputCallback ProcessStdOutputCallback { get; private set; }
|
|
|
public IDictionary<string, TypedArgument> Arguments { get; private set; }
|
|
public IDictionary<string, TypedArgument> Arguments { get; private set; }
|
|
|
public bool IsRunning { get; private set; }
|
|
public bool IsRunning { get; private set; }
|
|
|
public string ItemId { get; private set; }
|
|
public string ItemId { get; private set; }
|
|
|
|
|
|
|
|
- public PsProcessProviderBase(string itemId, TypedArgument[] arguments, ILogger logger)
|
|
|
|
|
|
|
+ #endregion
|
|
|
|
|
+
|
|
|
|
|
+ #region *** Private fields ***
|
|
|
|
|
+ private CancellationTokenSource? _cancelationToken;
|
|
|
|
|
+ #endregion
|
|
|
|
|
+
|
|
|
|
|
+ #region *** Constructors ***
|
|
|
|
|
+ public PsProcessProviderBase(ProcessDoneCallback processDoneCallback, ProcessStdOutputCallback processStdOutputCallback, string itemId, TypedArgument[] arguments, ILogger logger)
|
|
|
{
|
|
{
|
|
|
if (string.IsNullOrEmpty(itemId)) throw new ArgumentNullException(nameof(itemId));
|
|
if (string.IsNullOrEmpty(itemId)) throw new ArgumentNullException(nameof(itemId));
|
|
|
|
|
+ ProcessDoneCallback = processDoneCallback ?? throw new ArgumentNullException(nameof(processDoneCallback));
|
|
|
|
|
+ ProcessStdOutputCallback = processStdOutputCallback ?? throw new ArgumentNullException(nameof(processStdOutputCallback));
|
|
|
ItemId = itemId;
|
|
ItemId = itemId;
|
|
|
Log = logger.GetLogger(GetType());
|
|
Log = logger.GetLogger(GetType());
|
|
|
Arguments = arguments.ToDictionary(x => x.Name, x => x);
|
|
Arguments = arguments.ToDictionary(x => x.Name, x => x);
|
|
|
|
|
+ _cancelationToken = new CancellationTokenSource();
|
|
|
}
|
|
}
|
|
|
- #region Overrides of DisposableObject
|
|
|
|
|
-
|
|
|
|
|
- /// <inheritdoc />
|
|
|
|
|
- protected override void OnDisposing()
|
|
|
|
|
- {
|
|
|
|
|
- throw new NotImplementedException();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
#endregion
|
|
#endregion
|
|
|
|
|
|
|
|
- #region Implementation of IPsProcessProvider
|
|
|
|
|
|
|
+ #region *** Public Operations ***
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
/// <inheritdoc />
|
|
|
public void Validate()
|
|
public void Validate()
|
|
|
{
|
|
{
|
|
|
|
|
+ OnValidate();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
/// <inheritdoc />
|
|
/// <inheritdoc />
|
|
|
public async Task Start()
|
|
public async Task Start()
|
|
|
{
|
|
{
|
|
|
|
|
+ if (IsRunning)
|
|
|
|
|
+ throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderIsRunning, GetType().Name, ItemId);
|
|
|
|
|
+
|
|
|
Validate();
|
|
Validate();
|
|
|
|
|
+ var dtStart = DateTime.Now;
|
|
|
|
|
+ IsRunning = true;
|
|
|
|
|
+ var timeout = GetArgumentValue<TimeSpan>(CS_ARG_PROCESS_TIMEOUT);
|
|
|
try
|
|
try
|
|
|
{
|
|
{
|
|
|
- await OnProcess();
|
|
|
|
|
|
|
+ await OnProcess().TimeoutAfter(timeout).ContinueWith(task =>
|
|
|
|
|
+ {
|
|
|
|
|
+ Log.Log(LogSeverityEnum.Info, $"Provider for ItemId='{ItemId}' done. Duration {(DateTime.Now - dtStart).ToReadableString()}.");
|
|
|
|
|
+ if (ProcessDoneCallback != null)
|
|
|
|
|
+ ProcessDoneCallback(ItemId, PsStatusEnum.DoneOk, "Succesfuly done.");
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
catch (Exception e)
|
|
catch (Exception e)
|
|
|
{
|
|
{
|
|
|
- await OnProcessError(e);
|
|
|
|
|
- Log.Log(LogSeverityEnum.Error, "Provider running failed.", e);
|
|
|
|
|
|
|
+ await OnProcessError(e).ContinueWith(task =>
|
|
|
|
|
+ {
|
|
|
|
|
+ Log.Log(LogSeverityEnum.Error, $"Provider running failed. Duration {(DateTime.Now - dtStart).ToReadableString()}.", e);
|
|
|
|
|
+ if (ProcessDoneCallback != null)
|
|
|
|
|
+ ProcessDoneCallback(ItemId, PsStatusEnum.DoneFailed, e.Message);
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
|
|
+ finally
|
|
|
|
|
+ {
|
|
|
|
|
+ IsRunning = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// <inheritdoc />
|
|
|
|
|
+ public async void Stop()
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!IsRunning)
|
|
|
|
|
+ throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderNotRunning, GetType().Name, ItemId);
|
|
|
|
|
+
|
|
|
|
|
+ //TODO: stops here
|
|
|
|
|
+ }
|
|
|
|
|
+ #endregion
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ #region *** Protected Operations ***
|
|
|
|
|
+ protected TValue? GetArgumentValue<TValue>(string name)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (Arguments.TryGetValue(name, out var arg))
|
|
|
|
|
+ return arg.GetTypedValue<TValue>();
|
|
|
|
|
+ return default;
|
|
|
|
|
+ }
|
|
|
|
|
+ protected bool ContainsArgument(string name)
|
|
|
|
|
+ {
|
|
|
|
|
+ return Arguments.ContainsKey(name);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private async Task OnProcessError(Exception exception)
|
|
|
|
|
|
|
+ protected virtual void OnValidate()
|
|
|
{
|
|
{
|
|
|
- throw new NotImplementedException();
|
|
|
|
|
|
|
+ if (!ContainsArgument(CS_ARG_RESULT_CODE) || !Arguments[CS_ARG_RESULT_CODE].IsOutput)
|
|
|
|
|
+ throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderNotDefinedArgument, GetType().Name, ItemId, CS_ARG_RESULT_CODE);
|
|
|
|
|
+ if (!ContainsArgument(CS_ARG_RESULT_TEXT) || !Arguments[CS_ARG_RESULT_TEXT].IsOutput)
|
|
|
|
|
+ throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderNotDefinedArgument, GetType().Name, ItemId, CS_ARG_RESULT_TEXT);
|
|
|
|
|
+ if (!ContainsArgument(CS_ARG_PROCESS_TIMEOUT) || Arguments[CS_ARG_PROCESS_TIMEOUT].IsOutput)
|
|
|
|
|
+ throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderNotDefinedArgument, GetType().Name, ItemId, CS_ARG_PROCESS_TIMEOUT);
|
|
|
|
|
+ }
|
|
|
|
|
+ protected virtual async Task OnProcessError(Exception exception)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (ProcessStdOutputCallback != null)
|
|
|
|
|
+ ProcessStdOutputCallback(ItemId, exception.Message);
|
|
|
|
|
+
|
|
|
|
|
+ if (ContainsArgument(CS_ARG_RESULT_TEXT))
|
|
|
|
|
+ Arguments[CS_ARG_RESULT_TEXT].Value = exception.Message;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private async Task OnProcess()
|
|
|
|
|
|
|
+ protected virtual async Task OnProcess()
|
|
|
{
|
|
{
|
|
|
- throw new NotImplementedException();
|
|
|
|
|
|
|
+ //nothing to do
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
/// <inheritdoc />
|
|
|
- public async void Stop()
|
|
|
|
|
|
|
+ protected override void OnDisposing()
|
|
|
{
|
|
{
|
|
|
- throw new NotImplementedException();
|
|
|
|
|
|
|
+ ProcessDoneCallback = null!;
|
|
|
|
|
+ ProcessStdOutputCallback = null!;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
#endregion
|
|
#endregion
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
+
|
|
|
|
|
+}
|