PsProcessProviderBase.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. using qdr.fnd.core.pqueue.Enums;
  2. using qdr.fnd.core.pqueue.Exceptions;
  3. using Quadarax.Foundation.Core.Data;
  4. using Quadarax.Foundation.Core.Logging;
  5. using Quadarax.Foundation.Core.Object;
  6. using Quadarax.Foundation.Core.Thread.Extensions;
  7. using Quadarax.Foundation.Core.Value.Extensions;
  8. namespace qdr.fnd.core.pqueue.Process
  9. {
  10. public delegate void ProcessDoneCallback(string itemId, PsStatusEnum newStatus, string message);
  11. public delegate void ProcessStdOutputCallback(string itemId, string message);
  12. public abstract class PsProcessProviderBase : DisposableObject, IPsProcessProvider
  13. {
  14. #region *** Constants ***
  15. /// <summary>
  16. /// (Output) Argument name for the result code. Type is <see cref="long"/>
  17. /// </summary>
  18. public const string CS_ARG_RESULT_CODE = "result-code";
  19. /// <summary>
  20. /// (Output) Argument name for the result test. Type is <see cref="string"/>
  21. /// </summary>
  22. public const string CS_ARG_RESULT_TEXT = "result-text";
  23. /// <summary>
  24. /// (Input) Argument name for process timeout. Type is <see cref="TimeSpan"/>
  25. /// </summary>
  26. public const string CS_ARG_PROCESS_TIMEOUT = "process-timeout";
  27. #endregion
  28. #region *** Properties ***
  29. protected ILog Log { get; private set; }
  30. protected ProcessDoneCallback ProcessDoneCallback { get; private set; }
  31. protected ProcessStdOutputCallback ProcessStdOutputCallback { get; private set; }
  32. public IDictionary<string, TypedArgument> Arguments { get; private set; }
  33. public bool IsRunning { get; private set; }
  34. public string ItemId { get; private set; }
  35. #endregion
  36. #region *** Private fields ***
  37. private CancellationTokenSource? _cancelationToken;
  38. #endregion
  39. #region *** Constructors ***
  40. public PsProcessProviderBase(ProcessDoneCallback processDoneCallback, ProcessStdOutputCallback processStdOutputCallback, string itemId, TypedArgument[] arguments, ILogger logger)
  41. {
  42. if (string.IsNullOrEmpty(itemId)) throw new ArgumentNullException(nameof(itemId));
  43. ProcessDoneCallback = processDoneCallback ?? throw new ArgumentNullException(nameof(processDoneCallback));
  44. ProcessStdOutputCallback = processStdOutputCallback ?? throw new ArgumentNullException(nameof(processStdOutputCallback));
  45. ItemId = itemId;
  46. Log = logger.GetLogger(GetType());
  47. Arguments = arguments.ToDictionary(x => x.Name, x => x);
  48. _cancelationToken = new CancellationTokenSource();
  49. }
  50. #endregion
  51. #region *** Public Operations ***
  52. /// <inheritdoc />
  53. public void Validate()
  54. {
  55. OnValidate();
  56. }
  57. /// <inheritdoc />
  58. public async Task Start()
  59. {
  60. if (IsRunning)
  61. throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderIsRunning, GetType().Name, ItemId);
  62. Validate();
  63. var dtStart = DateTime.Now;
  64. IsRunning = true;
  65. var timeout = GetArgumentValue<TimeSpan>(CS_ARG_PROCESS_TIMEOUT);
  66. try
  67. {
  68. await OnProcess().TimeoutAfter(timeout).ContinueWith(task =>
  69. {
  70. Log.Log(LogSeverityEnum.Info, $"Provider for ItemId='{ItemId}' done. Duration {(DateTime.Now - dtStart).ToReadableString()}.");
  71. if (ProcessDoneCallback != null)
  72. ProcessDoneCallback(ItemId, PsStatusEnum.DoneOk, "Succesfuly done.");
  73. });
  74. }
  75. catch (Exception e)
  76. {
  77. await OnProcessError(e).ContinueWith(task =>
  78. {
  79. Log.Log(LogSeverityEnum.Error, $"Provider running failed. Duration {(DateTime.Now - dtStart).ToReadableString()}.", e);
  80. if (ProcessDoneCallback != null)
  81. ProcessDoneCallback(ItemId, PsStatusEnum.DoneFailed, e.Message);
  82. });
  83. }
  84. finally
  85. {
  86. IsRunning = false;
  87. }
  88. }
  89. /// <inheritdoc />
  90. public async void Stop()
  91. {
  92. if (!IsRunning)
  93. throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderNotRunning, GetType().Name, ItemId);
  94. //TODO: stops here
  95. }
  96. #endregion
  97. #region *** Protected Operations ***
  98. protected TValue? GetArgumentValue<TValue>(string name)
  99. {
  100. if (Arguments.TryGetValue(name, out var arg))
  101. return arg.GetTypedValue<TValue>();
  102. return default;
  103. }
  104. protected bool ContainsArgument(string name)
  105. {
  106. return Arguments.ContainsKey(name);
  107. }
  108. protected virtual void OnValidate()
  109. {
  110. if (!ContainsArgument(CS_ARG_RESULT_CODE) || !Arguments[CS_ARG_RESULT_CODE].IsOutput)
  111. throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderNotDefinedArgument, GetType().Name, ItemId, CS_ARG_RESULT_CODE);
  112. if (!ContainsArgument(CS_ARG_RESULT_TEXT) || !Arguments[CS_ARG_RESULT_TEXT].IsOutput)
  113. throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderNotDefinedArgument, GetType().Name, ItemId, CS_ARG_RESULT_TEXT);
  114. if (!ContainsArgument(CS_ARG_PROCESS_TIMEOUT) || Arguments[CS_ARG_PROCESS_TIMEOUT].IsOutput)
  115. throw new PsProcessProviderException(PsProcessProviderException.ErrorCodes.ProcessProviderNotDefinedArgument, GetType().Name, ItemId, CS_ARG_PROCESS_TIMEOUT);
  116. }
  117. protected virtual async Task OnProcessError(Exception exception)
  118. {
  119. if (ProcessStdOutputCallback != null)
  120. ProcessStdOutputCallback(ItemId, exception.Message);
  121. if (ContainsArgument(CS_ARG_RESULT_TEXT))
  122. Arguments[CS_ARG_RESULT_TEXT].Value = exception.Message;
  123. }
  124. protected virtual async Task OnProcess()
  125. {
  126. //nothing to do
  127. }
  128. /// <inheritdoc />
  129. protected override void OnDisposing()
  130. {
  131. ProcessDoneCallback = null!;
  132. ProcessStdOutputCallback = null!;
  133. }
  134. #endregion
  135. }
  136. }