public async Task <IActionResult> Rollback(string transactionKey, string errorCode = null, string errorMessage = null, bool isFatal = false) { try { Guid transactionKeyId = Guid.Parse(transactionKey); QueueItem queueItem = await manager.GetQueueItem(transactionKeyId); if (queueItem == null) { ModelState.AddModelError("Rollback", "Transaction key cannot be found."); return(BadRequest(ModelState)); } Guid queueItemId = (Guid)queueItem.Id; Guid queueId = queueItem.QueueId; Queue queue = queueRepository.GetOne(queueId); int retryLimit = queue.MaxRetryCount; if (retryLimit == null || retryLimit == 0) { retryLimit = int.Parse(Configuration["Queue.Global:DefaultMaxRetryCount"]); } await manager.Rollback(queueItemId, transactionKeyId, retryLimit, errorCode, errorMessage, isFatal); return(Ok()); } catch (Exception ex) { ModelState.AddModelError("Rollback", ex.Message); return(BadRequest(ModelState)); } }
public Queue CheckReferentialIntegrity(string id) { Guid entityId = new Guid(id); var existingQueue = _queueRepo.GetOne(entityId); if (existingQueue == null) { throw new EntityDoesNotExistException("Queue could not be found"); } var lockedQueueItems = _queueItemRepo.Find(0, 1).Items? .Where(q => q.QueueId == entityId && q.IsLocked); bool lockedChildExists = lockedQueueItems.Count() > 0; if (lockedChildExists) { throw new EntityOperationException("Referential integrity in queue items table; please remove any locked items associated with this queue first"); } return(existingQueue); }
public void SetNewState(QueueItem item) { item.RetryCount += 1; Guid queueId = item.QueueId; Queue queue = queueRepository.GetOne(queueId); int retryLimit = queue.MaxRetryCount; if (item.RetryCount < retryLimit) { item.State = QueueItemStateType.New.ToString(); item.StateMessage = $"Queue item {item.Name}'s lock time has expired and failed {item.RetryCount} time(s). Adding back to queue and trying again."; } else { item.State = QueueItemStateType.Failed.ToString(); item.StateMessage = $"Queue item transaction {item.Name} failed fatally and was unable to be automated {retryLimit} times."; } item.IsLocked = false; item.LockedBy = null; item.LockedEndTimeUTC = null; item.LockedUntilUTC = null; item.LockTransactionKey = null; }
public async Task <QueueItem> Rollback(Guid transactionKey, string errorCode = null, string errorMessage = null, bool isFatal = false) { QueueItem queueItem = await GetQueueItem(transactionKey); if (queueItem == null) { throw new EntityDoesNotExistException("Transaction key cannot be found"); } Guid queueItemId = queueItem.Id.Value; Guid queueId = queueItem.QueueId; Queue queue = _queueRepository.GetOne(queueId); int retryLimit = queue.MaxRetryCount; if (retryLimit == null || retryLimit == 0) { retryLimit = int.Parse(Configuration["Queue.Global:DefaultMaxRetryCount"]); } var item = _repo.GetOne(queueItemId); if (item == null) { throw new EntityDoesNotExistException("QueueItem does not exist or you do not have authorized access."); } UpdateItemsStates(item.QueueId.ToString()); if (item.State == "Failed") { throw new EntityOperationException(item.StateMessage); } if (item?.LockedUntilUTC < DateTime.UtcNow) { SetNewState(item); item.ErrorCode = errorCode; item.ErrorMessage = errorMessage; Dictionary <string, string> error = new Dictionary <string, string>(); if (!string.IsNullOrEmpty(errorCode)) { error.Add(errorCode, errorMessage); } item.ErrorSerialized = JsonConvert.SerializeObject(error); _repo.Update(item); return(item); } else if (item?.IsLocked == true && item?.LockedUntilUTC >= DateTime.UtcNow && item?.LockTransactionKey == transactionKey) { item.IsLocked = false; item.LockTransactionKey = null; item.LockedEndTimeUTC = DateTime.UtcNow; item.LockedBy = null; item.LockedUntilUTC = null; item.RetryCount += 1; item.ErrorCode = errorCode; item.ErrorMessage = errorMessage; Dictionary <string, string> error = new Dictionary <string, string>(); if (!string.IsNullOrEmpty(errorCode)) { error.Add(errorCode, errorMessage); } item.ErrorSerialized = JsonConvert.SerializeObject(error); if (isFatal) { item.State = QueueItemStateType.Failed.ToString(); item.StateMessage = $"Queue item transaction {item.Name} has failed fatally."; } else { if (item.RetryCount < retryLimit) { item.State = QueueItemStateType.New.ToString(); item.StateMessage = $"Queue item transaction {item.Name} failed {item.RetryCount} time(s). Adding back to queue and trying again."; } else { item.State = QueueItemStateType.Failed.ToString(); item.StateMessage = $"Queue item transaction {item.Name} failed fatally and was unable to be automated {retryLimit} times."; } } _repo.Update(item); return(item); } else { throw new Exception("Transaction key mismatched or expired. Cannot rollback."); } }