public virtual void InsertHistoryEntry(ScheduleTaskHistory historyEntry)
        {
            Guard.NotNull(historyEntry, nameof(historyEntry));

            applicationDbContext.ScheduleTaskHistories.Add(historyEntry);
            applicationDbContext.SaveChanges();
        }
Example #2
0
        public virtual void DeleteHistoryEntry(ScheduleTaskHistory historyEntry)
        {
            Guard.NotNull(historyEntry, nameof(historyEntry));
            Guard.IsTrue(!historyEntry.IsRunning, nameof(historyEntry.IsRunning), "Cannot delete a running schedule task history entry.");

            _taskHistoryRepository.Delete(historyEntry);
        }
        public virtual void DeleteHistoryEntry(ScheduleTaskHistory historyEntry)
        {
            Guard.NotNull(historyEntry, nameof(historyEntry));
            Guard.IsTrue(!historyEntry.IsRunning, nameof(historyEntry.IsRunning), "Cannot delete a running schedule task history entry.");

            applicationDbContext.ScheduleTaskHistories.Remove(historyEntry);
            applicationDbContext.SaveChanges();
        }
Example #4
0
        /// <summary>
        /// Creates and prepares a schedule task view model.
        /// </summary>
        /// <param name="task">Schedule task.</param>
        /// <param name="lastEntry">Last task history entry.</param>
        /// <returns>Schedule task model.</returns>
        public ScheduleTaskModel CreateScheduleTaskModel(ScheduleTask task, ScheduleTaskHistory lastEntry)
        {
            if (task == null)
            {
                return(null);
            }

            var now           = DateTime.UtcNow;
            var nextRunPretty = string.Empty;
            var isOverdue     = false;

            TimeSpan?dueIn = task.NextRunUtc.HasValue
                ? task.NextRunUtc.Value - now
                : (TimeSpan?)null;

            if (dueIn.HasValue)
            {
                if (dueIn.Value.TotalSeconds > 0)
                {
                    nextRunPretty = dueIn.Value.Prettify();
                }
                else
                {
                    nextRunPretty = T("Common.Waiting") + "...";
                    isOverdue     = true;
                }
            }

            var model = new ScheduleTaskModel
            {
                Id              = task.Id,
                Name            = task.Name,
                CronExpression  = task.CronExpression,
                CronDescription = CronExpression.GetFriendlyDescription(task.CronExpression),
                Enabled         = task.Enabled,
                Priority        = task.Priority,
                RunPerMachine   = task.RunPerMachine,
                StopOnError     = task.StopOnError,
                NextRunPretty   = nextRunPretty,
                CancelUrl       = _urlHelper.Action("CancelJob", "ScheduleTask", new { id = task.Id }),
                ExecuteUrl      = _urlHelper.Action("RunJob", "ScheduleTask", new { id = task.Id }),
                EditUrl         = _urlHelper.Action("Edit", "ScheduleTask", new { id = task.Id }),
                IsOverdue       = isOverdue
            };

            if (task.NextRunUtc.HasValue)
            {
                model.NextRun = _dateTimeHelper.ConvertToUserTime(task.NextRunUtc.Value, DateTimeKind.Utc);
            }

            model.LastHistoryEntry = CreateScheduleTaskHistoryModel(lastEntry);

            return(model);
        }
Example #5
0
        public virtual void UpdateHistoryEntry(ScheduleTaskHistory historyEntry)
        {
            Guard.NotNull(historyEntry, nameof(historyEntry));

            try
            {
                _taskHistoryRepository.Update(historyEntry);
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
                // Do not throw.
            }
        }
        public virtual void UpdateHistoryEntry(ScheduleTaskHistory historyEntry)
        {
            Guard.NotNull(historyEntry, nameof(historyEntry));

            try
            {
                applicationDbContext.Entry(historyEntry).State = System.Data.Entity.EntityState.Modified;
                applicationDbContext.SaveChanges();
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
                // Do not throw.
            }
        }
Example #7
0
        /// <summary>
        /// Creates and prepares a schedule task history view model.
        /// </summary>
        /// <param name="historyEntry">Schedule task history.</param>
        /// <returns>Schedule task history model.</returns>
        public ScheduleTaskHistoryModel CreateScheduleTaskHistoryModel(ScheduleTaskHistory historyEntry)
        {
            if (historyEntry == null)
            {
                return(new ScheduleTaskHistoryModel());
            }

            var model = new ScheduleTaskHistoryModel
            {
                Id              = historyEntry.Id,
                ScheduleTaskId  = historyEntry.ScheduleTaskId,
                IsRunning       = historyEntry.IsRunning,
                Error           = historyEntry.Error.EmptyNull(),
                ProgressPercent = historyEntry.ProgressPercent,
                ProgressMessage = historyEntry.ProgressMessage,
                StartedOn       = _dateTimeHelper.ConvertToUserTime(historyEntry.StartedOnUtc, DateTimeKind.Utc),
                StartedOnPretty = historyEntry.StartedOnUtc.RelativeFormat(true, "f"),
                MachineName     = historyEntry.MachineName
            };

            model.StartedOnString = model.StartedOn.ToString("g");

            if (historyEntry.FinishedOnUtc.HasValue)
            {
                model.FinishedOn       = _dateTimeHelper.ConvertToUserTime(historyEntry.FinishedOnUtc.Value, DateTimeKind.Utc);
                model.FinishedOnString = model.FinishedOn.Value.ToString("g");
                model.FinishedOnPretty = historyEntry.FinishedOnUtc.Value.RelativeFormat(true, "f");
            }

            if (historyEntry.SucceededOnUtc.HasValue)
            {
                model.SucceededOn       = _dateTimeHelper.ConvertToUserTime(historyEntry.SucceededOnUtc.Value, DateTimeKind.Utc);
                model.SucceededOnPretty = historyEntry.SucceededOnUtc.Value.ToNativeString("G");
            }

            var span = model.IsRunning
                ? DateTime.UtcNow - historyEntry.StartedOnUtc
                : (historyEntry.FinishedOnUtc ?? historyEntry.StartedOnUtc) - historyEntry.StartedOnUtc;

            if (span > TimeSpan.Zero)
            {
                model.Duration = span.ToString("g");
            }

            return(model);
        }
 public static ScheduleTaskHistoryDTO FromEntity(ScheduleTaskHistory item)
 {
     return(new ScheduleTaskHistoryDTO()
     {
         Id = item.Id,
         ScheduleTaskId = item.ScheduleTaskId,
         IsRunning = item.IsRunning,
         MachineName = item.MachineName,
         StartedOnUtc = item.StartedOnUtc,
         FinishedOnUtc = item.FinishedOnUtc,
         SucceededOnUtc = item.SucceededOnUtc,
         Error = item.Error,
         ProgressPercent = item.ProgressPercent,
         ProgressMessage = item.ProgressMessage,
         ScheduleTask = item.ScheduleTask != null?ScheduleTaskDTO.FromEntity(item.ScheduleTask) : null,
     });
 }
        /// <summary>
        /// Creates a transient context, which can be passed to methods requiring a <see cref="TaskExecutionContext"/> instance.
        /// Such methods are usually executed by the task executor in the background. If a manual invocation of such
        /// methods is required, this is the way to go.
        /// </summary>
        /// <param name="componentContext">The component context</param>
        /// <param name="cancellationToken">The cancellation token</param>
        /// <returns>A transient context</returns>
        public static TaskExecutionContext CreateTransientContext(IComponentContext componentContext, CancellationToken cancellationToken)
        {
            var originalHistoryEntry = new ScheduleTaskHistory
            {
                ScheduleTask = new ScheduleTask
                {
                    Name     = "Transient",
                    IsHidden = true,
                    Enabled  = true
                }
            };

            var context = new TransientTaskExecutionContext(componentContext, originalHistoryEntry);

            context.CancellationToken   = cancellationToken;
            context.ScheduleTaskHistory = originalHistoryEntry.Clone();

            return(context);
        }
 internal TaskExecutionContext(IComponentContext componentContext, ScheduleTaskHistory originalTaskHistory)
 {
     _componentContext    = componentContext;
     _originalTaskHistory = originalTaskHistory;
     Parameters           = new Dictionary <string, string>();
 }
 public TransientTaskExecutionContext(IComponentContext componentContext, ScheduleTaskHistory originalHistoryEntry)
     : base(componentContext, originalHistoryEntry)
 {
 }
Example #12
0
        public virtual void InsertHistoryEntry(ScheduleTaskHistory historyEntry)
        {
            Guard.NotNull(historyEntry, nameof(historyEntry));

            _taskHistoryRepository.Insert(historyEntry);
        }
Example #13
0
        private void PrepareProfileModel(
            ImportProfileModel model,
            ImportProfile profile,
            ScheduleTaskHistory lastHistoryEntry,
            bool forEdit,
            ColumnMap invalidMap = null)
        {
            model.Id                = profile.Id;
            model.Name              = profile.Name;
            model.EntityType        = profile.EntityType;
            model.Enabled           = profile.Enabled;
            model.ImportRelatedData = profile.ImportRelatedData;
            model.Skip              = profile.Skip == 0 ? (int?)null : profile.Skip;
            model.Take              = profile.Take == 0 ? (int?)null : profile.Take;
            model.UpdateOnly        = profile.UpdateOnly;
            model.KeyFieldNames     = profile.KeyFieldNames.SplitSafe(",").Distinct().ToArray();
            model.ScheduleTaskId    = profile.SchedulingTaskId;
            model.ScheduleTaskName  = profile.ScheduleTask.Name.NaIfEmpty();
            model.IsTaskRunning     = lastHistoryEntry?.IsRunning ?? false;
            model.IsTaskEnabled     = profile.ScheduleTask.Enabled;
            model.LogFileExists     = System.IO.File.Exists(profile.GetImportLogPath());
            model.EntityTypeName    = profile.EntityType.GetLocalizedEnum(Services.Localization, Services.WorkContext);
            model.ExistingFiles     = profile.GetImportFiles();

            foreach (var file in model.ExistingFiles)
            {
                if (file.RelatedType.HasValue)
                {
                    file.Label = string.Concat(T("Admin.Common.Data"), " ", file.RelatedType.Value.GetLocalizedEnum(Services.Localization, Services.WorkContext));
                }
            }

            if (profile.ResultInfo.HasValue())
            {
                model.ImportResult = XmlHelper.Deserialize <SerializableImportResult>(profile.ResultInfo);
            }

            if (!forEdit)
            {
                return;
            }

            CsvConfiguration csvConfiguration = null;

            if (profile.FileType == ImportFileType.CSV)
            {
                var csvConverter = new CsvConfigurationConverter();
                csvConfiguration = csvConverter.ConvertFrom <CsvConfiguration>(profile.FileTypeConfiguration) ?? CsvConfiguration.ExcelFriendlyConfiguration;

                model.CsvConfiguration = new CsvConfigurationModel(csvConfiguration);
            }
            else
            {
                csvConfiguration = CsvConfiguration.ExcelFriendlyConfiguration;
            }

            // Common configuration.
            var extraData = XmlHelper.Deserialize <ImportExtraData>(profile.ExtraData);

            model.ExtraData.NumberOfPictures = extraData.NumberOfPictures;

            // Column mapping.
            model.AvailableSourceColumns    = new List <ColumnMappingItemModel>();
            model.AvailableEntityProperties = new List <ColumnMappingItemModel>();
            model.AvailableKeyFieldNames    = new List <SelectListItem>();
            model.ColumnMappings            = new List <ColumnMappingItemModel>();

            model.FolderName = profile.GetImportFolder(absolutePath: false);

            try
            {
                string[] availableKeyFieldNames    = null;
                string[] disabledDefaultFieldNames = GetDisabledDefaultFieldNames(profile);
                var      mapConverter = new ColumnMapConverter();
                var      storedMap    = mapConverter.ConvertFrom <ColumnMap>(profile.ColumnMapping);
                var      map          = (invalidMap ?? storedMap) ?? new ColumnMap();

                // Property name to localized property name.
                var allProperties = _importProfileService.GetImportableEntityProperties(profile.EntityType) ?? new Dictionary <string, string>();

                switch (profile.EntityType)
                {
                case ImportEntityType.Product:
                    availableKeyFieldNames = ProductImporter.SupportedKeyFields;
                    break;

                case ImportEntityType.Category:
                    availableKeyFieldNames = CategoryImporter.SupportedKeyFields;
                    break;

                case ImportEntityType.Customer:
                    availableKeyFieldNames = CustomerImporter.SupportedKeyFields;
                    break;

                case ImportEntityType.NewsLetterSubscription:
                    availableKeyFieldNames = NewsLetterSubscriptionImporter.SupportedKeyFields;
                    break;
                }

                model.AvailableEntityProperties = allProperties
                                                  .Select(x =>
                {
                    var mapping = new ColumnMappingItemModel
                    {
                        Property            = x.Key,
                        PropertyDescription = x.Value,
                        IsDefaultDisabled   = IsDefaultValueDisabled(x.Key, x.Key, disabledDefaultFieldNames)
                    };

                    return(mapping);
                })
                                                  .ToList();

                model.AvailableKeyFieldNames = availableKeyFieldNames
                                               .Select(x =>
                {
                    var item = new SelectListItem {
                        Value = x, Text = x
                    };

                    if (x == "Id")
                    {
                        item.Text = T("Admin.Common.Entity.Fields.Id");
                    }
                    else if (allProperties.ContainsKey(x))
                    {
                        item.Text = allProperties[x];
                    }

                    return(item);
                })
                                               .ToList();

                model.ColumnMappings = map.Mappings
                                       .Select(x =>
                {
                    var mapping = new ColumnMappingItemModel
                    {
                        Column   = x.Value.MappedName,
                        Property = x.Key,
                        Default  = x.Value.Default
                    };

                    if (x.Value.IgnoreProperty)
                    {
                        // Explicitly ignore the property.
                        mapping.Column  = null;
                        mapping.Default = null;
                    }

                    mapping.PropertyDescription = GetPropertyDescription(allProperties, mapping.Property);
                    mapping.IsDefaultDisabled   = IsDefaultValueDisabled(mapping.Column, mapping.Property, disabledDefaultFieldNames);

                    return(mapping);
                })
                                       .ToList();

                var file = model.ExistingFiles.FirstOrDefault(x => !x.RelatedType.HasValue);
                if (file == null)
                {
                    return;
                }

                using (var stream = new FileStream(file.Path, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    var dataTable = LightweightDataTable.FromFile(Path.GetFileName(file.Path), stream, stream.Length, csvConfiguration, 0, 1);

                    foreach (var column in dataTable.Columns.Where(x => x.Name.HasValue()))
                    {
                        string columnWithoutIndex, columnIndex;
                        ColumnMap.ParseSourceName(column.Name, out columnWithoutIndex, out columnIndex);

                        model.AvailableSourceColumns.Add(new ColumnMappingItemModel
                        {
                            Index               = dataTable.Columns.IndexOf(column),
                            Column              = column.Name,
                            ColumnWithoutIndex  = columnWithoutIndex,
                            ColumnIndex         = columnIndex,
                            PropertyDescription = GetPropertyDescription(allProperties, column.Name)
                        });

                        // Auto map where field equals property name.
                        if (!model.ColumnMappings.Any(x => x.Column == column.Name))
                        {
                            var kvp = allProperties.FirstOrDefault(x => x.Key.IsCaseInsensitiveEqual(column.Name));
                            if (kvp.Key.IsEmpty())
                            {
                                var alternativeName = LightweightDataTable.GetAlternativeColumnNameFor(column.Name);
                                kvp = allProperties.FirstOrDefault(x => x.Key.IsCaseInsensitiveEqual(alternativeName));
                            }

                            if (kvp.Key.HasValue() && !model.ColumnMappings.Any(x => x.Property == kvp.Key))
                            {
                                model.ColumnMappings.Add(new ColumnMappingItemModel
                                {
                                    Column              = column.Name,
                                    Property            = kvp.Key,
                                    PropertyDescription = kvp.Value,
                                    IsDefaultDisabled   = IsDefaultValueDisabled(column.Name, kvp.Key, disabledDefaultFieldNames)
                                });
                            }
                        }
                    }

                    // Sorting.
                    model.AvailableSourceColumns = model.AvailableSourceColumns
                                                   .OrderBy(x => x.PropertyDescription)
                                                   .ToList();

                    model.AvailableEntityProperties = model.AvailableEntityProperties
                                                      .OrderBy(x => x.PropertyDescription)
                                                      .ToList();

                    model.ColumnMappings = model.ColumnMappings
                                           .OrderBy(x => x.PropertyDescription)
                                           .ToList();
                }
            }
            catch (Exception ex)
            {
                NotifyError(ex, true, false);
            }
        }
Example #14
0
        public void Execute(
            ScheduleTask task,
            IDictionary <string, string> taskParameters = null,
            bool throwOnError = false)
        {
            if (AsyncRunner.AppShutdownCancellationToken.IsCancellationRequested)
            {
                return;
            }

            if (task.LastHistoryEntry == null)
            {
                // The task was started manually.
                task.LastHistoryEntry = _scheduledTaskService.GetLastHistoryEntryByTaskId(task.Id);
            }

            if (task?.LastHistoryEntry?.IsRunning == true)
            {
                return;
            }

            bool      faulted   = false;
            bool      canceled  = false;
            string    lastError = null;
            ITask     instance  = null;
            string    stateName = null;
            Type      taskType  = null;
            Exception exception = null;

            var historyEntry = new ScheduleTaskHistory
            {
                ScheduleTaskId = task.Id,
                IsRunning      = true,
                MachineName    = _env.MachineName,
                StartedOnUtc   = DateTime.UtcNow
            };

            try
            {
                taskType = Type.GetType(task.Type);
                if (taskType == null)
                {
                    Logger.DebugFormat("Invalid scheduled task type: {0}", task.Type.NaIfEmpty());
                }

                if (taskType == null)
                {
                    return;
                }

                if (!PluginManager.IsActivePluginAssembly(taskType.Assembly))
                {
                    return;
                }

                task.ScheduleTaskHistory.Add(historyEntry);
                _scheduledTaskService.UpdateTask(task);
            }
            catch
            {
                return;
            }

            try
            {
                // Task history entry has been successfully added, now we execute the task.
                // Create task instance.
                instance  = _taskResolver(taskType);
                stateName = task.Id.ToString();

                // Create & set a composite CancellationTokenSource which also contains the global app shoutdown token.
                var cts = CancellationTokenSource.CreateLinkedTokenSource(AsyncRunner.AppShutdownCancellationToken, new CancellationTokenSource().Token);
                _asyncState.SetCancelTokenSource <ScheduleTask>(cts, stateName);

                var ctx = new TaskExecutionContext(_componentContext, historyEntry)
                {
                    ScheduleTaskHistory = historyEntry.Clone(),
                    CancellationToken   = cts.Token,
                    Parameters          = taskParameters ?? new Dictionary <string, string>()
                };

                Logger.DebugFormat("Executing scheduled task: {0}", task.Type);
                instance.Execute(ctx);
            }
            catch (Exception ex)
            {
                exception = ex;
                faulted   = true;
                canceled  = ex is OperationCanceledException;
                lastError = ex.Message.Truncate(995, "...");

                if (canceled)
                {
                    Logger.Warn(ex, T("Admin.System.ScheduleTasks.Cancellation", task.Name));
                }
                else
                {
                    Logger.Error(ex, string.Concat(T("Admin.System.ScheduleTasks.RunningError", task.Name), ": ", ex.Message));
                }
            }
            finally
            {
                var now        = DateTime.UtcNow;
                var updateTask = false;

                historyEntry.IsRunning       = false;
                historyEntry.ProgressPercent = null;
                historyEntry.ProgressMessage = null;
                historyEntry.Error           = lastError;
                historyEntry.FinishedOnUtc   = now;

                if (faulted)
                {
                    if ((!canceled && task.StopOnError) || instance == null)
                    {
                        task.Enabled = false;
                        updateTask   = true;
                    }
                }
                else
                {
                    historyEntry.SucceededOnUtc = now;
                }

                try
                {
                    Logger.DebugFormat("Executed scheduled task: {0}. Elapsed: {1} ms.", task.Type, (now - historyEntry.StartedOnUtc).TotalMilliseconds);

                    // Remove from AsyncState.
                    if (stateName.HasValue())
                    {
                        _asyncState.Remove <ScheduleTask>(stateName);
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error(ex);
                }

                if (task.Enabled)
                {
                    task.NextRunUtc = _scheduledTaskService.GetNextSchedule(task);
                    updateTask      = true;
                }

                _scheduledTaskService.UpdateHistoryEntry(historyEntry);

                if (updateTask)
                {
                    _scheduledTaskService.UpdateTask(task);
                }

                Throttle.Check("Delete old schedule task history entries", TimeSpan.FromDays(1), () => _scheduledTaskService.DeleteHistoryEntries() > 0);
            }

            if (throwOnError && exception != null)
            {
                throw exception;
            }
        }
Example #15
0
 public async Task UpdateScheduleTaskHistory(ScheduleTaskHistory scheduleTaskHistory)
 {
     await _scheduleTaskHistoryRepository.UpdateAsync(scheduleTaskHistory);
 }
Example #16
0
 public async Task CreateScheduleTaskHistory(ScheduleTaskHistory scheduleTaskHistory)
 {
     await _scheduleTaskHistoryRepository.AddAsync(scheduleTaskHistory);
 }