예제 #1
0
 public UpdateCascadeOperationExecutor(DocumentDatabase db, UpdateCascadeSetting setting, UpdateCascadeOperation operation, JsonDocument referencedDoc)
 {
     this.db            = db;
     this.services      = Services.GetServices(db);
     this.setting       = setting;
     this.operation     = operation;
     this.referencedDoc = referencedDoc;
 }
예제 #2
0
 public void Execute(Database.DocumentDatabase database)
 {
     try
     {
         services = Services.GetServices(database);
         services.IsShutDownInProgress = false;
         db = database;
         this.db.PutIndex(UpdateCascadeOperation.ByStatusIndexName, UpdateCascadeOperation.GetByStatusIndexDefinition());
         Task.Factory.StartNew(services.RunningOperationsCoordinator.RestartNotCompletedOperations).ContinueWith(t =>
         {
             if (t.Status == TaskStatus.Faulted && t.Exception != null)
             {
                 log.ErrorException("Failed to restart not completed operations", t.Exception);
             }
         });
     }
     catch (Exception ex)
     {
         log.FatalException("Failed to execute UpdateCascadeStartupTask", ex);
     }
 }
예제 #3
0
 public override void Initialize()
 {
     base.Initialize();
     services            = Services.GetServices(this.Database);
     operationRepository = new Repository <UpdateCascadeOperation>(this.Database);
 }
 public override void Initialize()
 {
     base.Initialize();
     services = Services.GetServices(this.Database);
 }
        public bool TryStartOperation(UpdateCascadeOperation operation, JsonDocument referencedDoc)
        {
            var services = Services.GetServices(this.db);

            if (services.IsShutDownInProgress)
            {
                log.Warn("Tried to start operation {0} while shuting down", operation.Id);
                return(false);
            }

            RunningOperation     ro = null;
            UpdateCascadeSetting setting;

            if (!services.SettingsCache.TryGetValue(operation.UpdateCascadeSettingId, out setting))
            {
                log.Error("Tried to add and run the operation {0}. But there is no corresponding setting {1}", operation.Id, operation.UpdateCascadeSettingId);
                return(false);
            }

            lock (runningOperations)
            {
                if (runningOperations.TryGetValue(operation.ReferencedDocId, out ro))
                {
                    // the operation might be already here. This shouldn't occur
                    if (operation.Id == ro.Operation.Id)
                    {
                        log.Warn("Tried to start an operation that is already started. Operation Id = {0}", operation.Id);
                        return(false);
                    }
                    // the operation might refer to an older entity. This is unprobable, I think
                    if (Buffers.Compare(operation.ReferencedDocEtag.ToByteArray(), ro.Operation.ReferencedDocEtag.ToByteArray()) < 0)
                    {
                        log.Warn("Tried to start an operation that refers to an entity which is older than the referenced by a running operation. Older operation id: {0}, existing operation id: {1}", operation.Id, ro.Operation.Id);
                        return(false);
                    }

                    log.Warn("The same referenced entity {0} has been updated while a previous update cascade operation of that entity is in progress, that might indicate that the document is updated so often that referencing entities cannot be updated at time. Update cascade bundle is not recomended in this scenario", operation.ReferencedDocId);

                    // the same referenced entity has been updated while a previous update cascade operation of that entity is in progress
                    // we need to cancel that operation and span a new one.
                    var tokenSource = ro.TokenSource;
                    if (tokenSource != null)
                    {
                        tokenSource.Cancel();
                    }
                    try
                    {
                        var task = ro.ExecutorTask;
                        if (task != null)
                        {
                            task.Wait();
                        }
                    }
                    catch (AggregateException ex)
                    {
                        ex.Handle(x => x is TaskCanceledException);
                    }
                }
                var runningOperation = new RunningOperation
                {
                    Operation   = operation,
                    TokenSource = new CancellationTokenSource(),
                    Executor    = new UpdateCascadeOperationExecutor(db, setting, operation, referencedDoc),
                };
                runningOperations[operation.ReferencedDocId] = runningOperation;
                log.Trace("Starting operation: {0}", operation.Id);
                runningOperation.ExecutorTask = runningOperation.Executor.ExecuteAsync(runningOperation.TokenSource.Token);
                runningOperation.ExecutorTask.ContinueWith(t =>
                {
                    if (!services.IsShutDownInProgress)
                    {
                        lock (runningOperations)
                        {
                            RunningOperation rop;
                            if (runningOperations.TryGetValue(operation.ReferencedDocId, out rop))
                            {
                                if (rop.Operation.Id == operation.Id)
                                {
                                    runningOperations.Remove(operation.ReferencedDocId);
                                }
                            }
                            t.Dispose();
                        }
                    }
                }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

                return(true);
            }
        }