* Started implementing new LongRunningOperationService and adjusting tasks to use this service This service will manage operations that require status to be synced between servers (load balanced setup). * Missing migration to add new lock. Other simplifications. * Add job to cleanup the LongRunningOperations entries * Add new DatabaseCacheRebuilder.RebuildAsync method This is both async and returns an attempt, which will fail if a rebuild operation is already running. * Missing LongRunningOperation database table creation on clean install * Store expire date in the long running operation. Better handling of non-background operations. Storing an expiration date allows setting different expiration times depending on the type of operation, and whether it is running in the background or not. * Added integration tests for LongRunningOperationRepository * Added unit tests for LongRunningOperationService * Add type as a parameter to more repository calls. Distinguish between expiration and deletion in `LongRunningOperationRepository.CleanOperations`. * Fix failing unit test * Fixed `PerformPublishBranchAsync` result not being deserialized correctly * Remove unnecessary DatabaseCacheRebuildResult value * Add status to `LongRunningOperationService.GetResult` attempt to inform on why a result could not be retrieved * General improvements * Missing rename * Improve the handling of long running operations that are not in background and stale operations * Fix failing unit tests * Fixed small mismatch between interface and implementation * Use a fire and forget task instead of the background queue * Apply suggestions from code review Co-authored-by: Andy Butland <abutland73@gmail.com> * Make sure exceptions are caught when running in the background * Alignment with other repositories (async + pagination) * Additional fixes * Add Async suffix to service methods * Missing adjustment * Moved hardcoded settings to IOptions * Fix issue in SQL Server where 0 is not accepted as requested number of rows * Fix issue in SQL Server where query provided to count cannot contain orderby * Additional SQL Server fixes --------- Co-authored-by: Andy Butland <abutland73@gmail.com>
125 lines
5.2 KiB
C#
125 lines
5.2 KiB
C#
using System.Text.Json.Serialization;
|
|
|
|
namespace Umbraco.Cms.Core;
|
|
|
|
/// <summary>
|
|
/// Represents the result of an operation attempt.
|
|
/// </summary>
|
|
/// <typeparam name="TResult">The type of the attempted operation result.</typeparam>
|
|
/// <typeparam name="TStatus">The type of the attempted operation status.</typeparam>
|
|
[Serializable]
|
|
public struct Attempt<TResult, TStatus>
|
|
{
|
|
// private - use Succeed() or Fail() methods to create attempts
|
|
[JsonConstructor]
|
|
private Attempt(bool success, TResult result, TStatus status, Exception? exception)
|
|
{
|
|
Success = success;
|
|
Result = result;
|
|
Status = status;
|
|
Exception = exception;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether this <see cref="Attempt{TResult,TStatus}" /> was successful.
|
|
/// </summary>
|
|
public bool Success { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the exception associated with an unsuccessful attempt.
|
|
/// </summary>
|
|
public Exception? Exception { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the attempt result.
|
|
/// </summary>
|
|
public TResult Result { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the attempt status.
|
|
/// </summary>
|
|
public TStatus Status { get; }
|
|
|
|
/// <summary>
|
|
/// Implicitly operator to check if the attempt was successful without having to access the 'success' property
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <returns></returns>
|
|
public static implicit operator bool(Attempt<TResult, TStatus> a) => a.Success;
|
|
|
|
/// <summary>
|
|
/// Creates a successful attempt.
|
|
/// </summary>
|
|
/// <param name="status">The status of the attempt.</param>
|
|
/// <returns>The successful attempt.</returns>
|
|
public static Attempt<TResult?, TStatus> Succeed(TStatus status) =>
|
|
new Attempt<TResult?, TStatus>(true, default, status, null);
|
|
|
|
/// <summary>
|
|
/// Creates a successful attempt with a result.
|
|
/// </summary>
|
|
/// <param name="status">The status of the attempt.</param>
|
|
/// <param name="result">The result of the attempt.</param>
|
|
/// <returns>The successful attempt.</returns>
|
|
public static Attempt<TResult, TStatus> Succeed(TStatus status, TResult result) =>
|
|
new Attempt<TResult, TStatus>(true, result, status, null);
|
|
|
|
/// <summary>
|
|
/// Creates a failed attempt.
|
|
/// </summary>
|
|
/// <param name="status">The status of the attempt.</param>
|
|
/// <returns>The failed attempt.</returns>
|
|
public static Attempt<TResult?, TStatus> Fail(TStatus status) =>
|
|
new Attempt<TResult?, TStatus>(false, default, status, null);
|
|
|
|
/// <summary>
|
|
/// Creates a failed attempt with an exception.
|
|
/// </summary>
|
|
/// <param name="status">The status of the attempt.</param>
|
|
/// <param name="exception">The exception causing the failure of the attempt.</param>
|
|
/// <returns>The failed attempt.</returns>
|
|
public static Attempt<TResult?, TStatus> Fail(TStatus status, Exception exception) =>
|
|
new Attempt<TResult?, TStatus>(false, default, status, exception);
|
|
|
|
/// <summary>
|
|
/// Creates a failed attempt with a result.
|
|
/// </summary>
|
|
/// <param name="status">The status of the attempt.</param>
|
|
/// <param name="result">The result of the attempt.</param>
|
|
/// <returns>The failed attempt.</returns>
|
|
public static Attempt<TResult, TStatus> Fail(TStatus status, TResult result) =>
|
|
new Attempt<TResult, TStatus>(false, result, status, null);
|
|
|
|
/// <summary>
|
|
/// Creates a failed attempt with a result and an exception.
|
|
/// </summary>
|
|
/// <param name="status">The status of the attempt.</param>
|
|
/// <param name="result">The result of the attempt.</param>
|
|
/// <param name="exception">The exception causing the failure of the attempt.</param>
|
|
/// <returns>The failed attempt.</returns>
|
|
public static Attempt<TResult, TStatus> Fail(TStatus status, TResult result, Exception exception) =>
|
|
new Attempt<TResult, TStatus>(false, result, status, exception);
|
|
|
|
/// <summary>
|
|
/// Creates a successful or a failed attempt.
|
|
/// </summary>
|
|
/// <param name="condition">A value indicating whether the attempt is successful.</param>
|
|
/// <param name="succStatus">The status of the successful attempt.</param>
|
|
/// <param name="failStatus">The status of the failed attempt.</param>
|
|
/// <returns>The attempt.</returns>
|
|
public static Attempt<TResult?, TStatus> If(bool condition, TStatus succStatus, TStatus failStatus) =>
|
|
new Attempt<TResult?, TStatus>(condition, default, condition ? succStatus : failStatus, null);
|
|
|
|
/// <summary>
|
|
/// Creates a successful or a failed attempt, with a result.
|
|
/// </summary>
|
|
/// <param name="condition">A value indicating whether the attempt is successful.</param>
|
|
/// <param name="succStatus">The status of the successful attempt.</param>
|
|
/// <param name="failStatus">The status of the failed attempt.</param>
|
|
/// <param name="result">The result of the attempt.</param>
|
|
/// <returns>The attempt.</returns>
|
|
public static Attempt<TResult, TStatus>
|
|
If(bool condition, TStatus succStatus, TStatus failStatus, TResult result) =>
|
|
new Attempt<TResult, TStatus>(condition, result, condition ? succStatus : failStatus, null);
|
|
}
|