private void UpdateCascadeReferencingCollection(ReferencingCollectionSetting rc, ReferencingCollectionOperation co) { co.StartedDate = DateTime.UtcNow; co.Status = UpdateCascadeOperationStatus.Executing; co.UpdatedDocumentCount = 0; SaveOperationSilentlyIgnoringError(); // we can continue anyway log.Trace("Update cascade {0} referencing document collection for update cascade operation {1} started", rc.ReferencingEntityName, operation.Id); try { int updatedByIndex = 0; Guid lastEtag; do { lastEtag = db.GetLastEtag(); var query = new IndexQuery { CutoffEtag = lastEtag, Query = string.Format("{0}:{1} AND {2}:{3}NULL TO {4}{5}", rc.ReferencedIdPropertyNameInIndex, RavenQuery.Escape(referencedDoc.Key), rc.ReferencedEtagPropertyNameInIndex, "{", RavenQuery.Escape(Convert.ToString(referencedDoc.Etag, CultureInfo.InvariantCulture)), "}") }; updatedByIndex = db.UpdateByIndex(rc.IndexName, query, doc => UpdateDocumentWithProgressReport(doc, co), TimeSpan.FromHours(8), cancellationToken, null); } while (updatedByIndex > 0); db.UpdateDocumentsAfter(lastEtag, UpdateDocument, cancellationToken, null); co.Status = UpdateCascadeOperationStatus.CompletedSuccessfully; log.Trace("Update cascade {0} documents for operation {1} completed successfully. {2} documents have been updated in {3}", rc.ReferencingEntityName, operation.Id, co.UpdatedDocumentCount, co.ElapsedTime); } catch (OperationCanceledException) // save the operation and rethrow { co.Status = UpdateCascadeOperationStatus.Canceled; throw; } catch (Exception ex) // Log the error, save the operation, and move to the next. { co.ErrorMessage = ex.Message; co.Status = UpdateCascadeOperationStatus.Failed; log.ErrorException(string.Format("Update cascade {0} documents for operation {1} failed miserably. Moving on the next one ...", rc.ReferencingEntityName, operation.Id), ex); } finally { co.CompletedDate = DateTime.UtcNow; if (!(services.IsShutDownInProgress && co.Status == UpdateCascadeOperationStatus.Canceled)) { SaveOperationSilentlyIgnoringError(); // we want to preserve OperationCanceledException. } } }
public void RestartNotCompletedOperations() { var lastEtag = db.GetLastEtag(); db.WaitForIndexNotStale(UpdateCascadeOperation.ByStatusIndexName, null, lastEtag, TimeSpan.FromHours(1), CancellationToken.None); var indexQuery = new IndexQuery { CutoffEtag = lastEtag, PageSize = 1024, Query = "Status:Pending OR Status:Executing" }; IList <string> docIds = null; int restartedOperations = 0; do { docIds = db.QueryDocumentIds(UpdateCascadeOperation.ByStatusIndexName, indexQuery, CancellationToken.None); indexQuery.Start += docIds.Count; db.TransactionalStorage.Batch(_ => { foreach (var id in docIds) { var operation = repository.Get(id); JsonDocument referenceDocument = null; if (operation != null) { referenceDocument = db.Get(operation.ReferencedDocId, null); } if (operation != null && referenceDocument != null && TryStartOperation(operation, referenceDocument)) { restartedOperations++; log.Debug("Operation {0} has been restarted after a reboot. {1} operations restarted so far", id, restartedOperations); } } }); } while (docIds.Count == indexQuery.PageSize); }