| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- using qdr.fnd.core.pqueue.Enums;
- using qdr.fnd.core.pqueue.Exceptions;
- using qdr.fnd.core.pqueue.fnd.candidates;
- using Quadarax.Foundation.Core.Data;
- using Quadarax.Foundation.Core.Logging;
- using Quadarax.Foundation.Core.Object;
- using Quadarax.Foundation.Core.Value.Extensions;
- namespace qdr.fnd.core.pqueue.Process
- {
- public delegate void ProcessDoneCallback(string itemId, PsStatusEnum newStatus, string message);
- public delegate void ProcessStdOutputCallback(string itemId, string message);
- public abstract class PsProcessProviderBase : DisposableObject, IPsProcessProvider
- {
- #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 bool IsRunning { get; private set; }
- public string ItemId { get; private set; }
- #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));
- ProcessDoneCallback = processDoneCallback ?? throw new ArgumentNullException(nameof(processDoneCallback));
- ProcessStdOutputCallback = processStdOutputCallback ?? throw new ArgumentNullException(nameof(processStdOutputCallback));
- ItemId = itemId;
- Log = logger.GetLogger(GetType());
- Arguments = arguments.ToDictionary(x => x.Name, x => x);
- _cancelationToken = new CancellationTokenSource();
- }
- #endregion
- #region *** Public Operations ***
- /// <inheritdoc />
- public void Validate()
- {
- OnValidate();
- }
- /// <inheritdoc />
- public void Start()
- {
- if (IsRunning)
- throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderIsRunning, GetType().Name, ItemId);
- Validate();
- IsRunning = true;
- var timeout = GetArgumentValue<TimeSpan>(CS_ARG_PROCESS_TIMEOUT);
- _ = Task.Factory.StartNew(() => StartInternal(timeout).TimeoutAfter(_cancelationToken!, timeout), _cancelationToken!.Token);
- }
- /// <inheritdoc />
- public void Stop()
- {
- if (!IsRunning)
- throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderNotRunning, GetType().Name, ItemId);
-
- _cancelationToken?.Cancel();
- IsRunning = false;
- }
- /// <summary>
- /// Generates all arguments collection
- /// </summary>
- /// <returns>Full scoped arguments collection</returns>
- public static IEnumerable<TypedArgument> CreateArguments()
- {
- var list = new List<TypedArgument>
- {
- new TypedArgument(CS_ARG_RESULT_CODE, typeof(long), true),
- new TypedArgument(CS_ARG_RESULT_TEXT, typeof(string), true),
- new TypedArgument(CS_ARG_PROCESS_TIMEOUT, typeof(TimeSpan), false)
- };
- return list;
- }
- /// <inheritdoc />
- public void WaitToDone()
- {
- while(IsRunning)
- {
- Task.Delay(100).Wait();
- };
- Log.Log(LogSeverityEnum.Debug, $"Provider for ItemId='{ItemId}' detect that process finished.");
- }
- #endregion
- #region *** Protected Operations ***
- protected TValue? GetArgumentValue<TValue>(string name)
- {
- if (string.IsNullOrEmpty(name))
- throw new ArgumentNullException(nameof(name));
- if (Arguments.TryGetValue(name, out var arg))
- return arg.GetTypedValue<TValue>();
- return default;
- }
- protected bool ContainsArgument(string name)
- {
- if (string.IsNullOrEmpty(name))
- throw new ArgumentNullException(nameof(name));
- return Arguments.ContainsKey(name);
- }
- protected virtual void OnValidate()
- {
- 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 (exception == null)
- throw new ArgumentNullException(nameof(exception));
- if (ProcessStdOutputCallback != null)
- ProcessStdOutputCallback(ItemId, exception.Message);
- if (ContainsArgument(CS_ARG_RESULT_TEXT))
- Arguments[CS_ARG_RESULT_TEXT].Value = exception.Message;
- }
- protected virtual async Task OnProcess()
- {
- //nothing to do
- }
- /// <inheritdoc />
- protected override void OnDisposing()
- {
- ProcessDoneCallback = null!;
- ProcessStdOutputCallback = null!;
- }
-
- private async Task StartInternal(TimeSpan timeout)
- {
- var dtStart = DateTime.Now;
- try
- {
- Log.Log(LogSeverityEnum.Debug, $"Provider for ItemId='{ItemId}' has general timeout for execution {timeout.ToReadableString()}.");
- await OnProcess().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.");
- IsRunning = false;
- });
-
- }
- catch (Exception 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);
- IsRunning = false;
- });
- }
- }
-
- #endregion
- }
- }
|