Пример #1
0
 /// <summary>
 /// Instantiates a background operation task queue directive that
 /// may include a wrapped internal directive.
 /// </summary>
 /// <param name="backgroundOperationName">The name of the background operation on which this task is run.</param>
 /// <param name="internalDirective">The directive - if any - to pass to the job.</param>
 public BackgroundOperationTaskDirective
 (
     string backgroundOperationName,
     TaskDirective internalDirective
 )
 {
     this.BackgroundOperationName = backgroundOperationName;
     this.InternalDirective       = internalDirective;
 }
Пример #2
0
 /// <summary>
 /// Cancels any future executions of tasks of type <paramref name="taskType"/> on queue <paramref name="queueId"/>.
 /// If <paramref name="scheduleFor"/> has a value then a new execution of the task is scheduled for this date/time.
 /// </summary>
 /// <param name="queueId">The queue that the task should be rescheduled on.</param>
 /// <param name="taskType">The task type to be rescheduled.</param>
 /// <param name="innerDirective">The inner directive to be passed to the rescheduled task.</param>
 /// <param name="vault">The vault reference to use for the operation.</param>
 /// <param name="scheduleFor">The date/time to schedule a new execution for.  If <see langword="null"/>, does not schedule a future execution.</param>
 /// <remarks>Adds an item to the scheduling queue, so that only one server performs this operation.</remarks>
 public virtual void RescheduleTask(string queueId, string taskType, TaskDirective innerDirective = null, Vault vault = null, DateTime?scheduleFor = null)
 => this.AddTask
 (
     vault ?? this.VaultApplication.PermanentVault,
     this.VaultApplication.GetSchedulerQueueID(),
     this.VaultApplication.GetRescheduleTaskType(),
     new RescheduleProcessorTaskDirective()
 {
     QueueID        = queueId,
     TaskType       = taskType,
     NextExecution  = scheduleFor,
     InnerDirective = innerDirective
 }
 );
Пример #3
0
 /// <summary>
 /// Creates a new background operation and starts it.
 /// The background operation runs the given method according to the <paramref name="schedule"/>.
 /// </summary>
 /// <param name="name">The name of the operation.</param>
 /// <param name="schedule">The schedule that defines when the operation should run.</param>
 /// <param name="method">The method to invoke at given intervals.</param>
 /// <param name="directive">The directive to pass to the job.</param>
 /// <returns>A started background operation.</returns>
 public TaskQueueBackgroundOperation <TSecureConfiguration> StartScheduledBackgroundOperation
 (
     string name,
     Schedule schedule,
     Action <TaskProcessorJobEx <BackgroundOperationTaskDirective, TSecureConfiguration>, TaskDirective> method,
     TaskDirective directive = null
 )
 {
     return(this.StartScheduledBackgroundOperation <TaskDirective>
            (
                name,
                schedule,
                method,
                directive
            ));
 }
Пример #4
0
 /// <summary>
 /// Creates a new background operation and starts it. The background operation runs the given method at given intervals.
 /// </summary>
 /// <param name="name">The name of the operation.</param>
 /// <param name="interval">The target interval between method calls. If the method call takes longer than the interval, the method will be invoked immediately after the previous method call returns.</param>
 /// <param name="method">The method to invoke at given intervals.</param>
 /// <param name="directive">The directive to pass to the job.</param>
 /// <param name="options">The options for the display of the background operation in the dashboard.</param>
 /// <returns>A started background operation.</returns>
 public TaskQueueBackgroundOperation <TSecureConfiguration> StartRecurringBackgroundOperation
 (
     string name,
     TimeSpan interval,
     Action <TaskProcessorJobEx <BackgroundOperationTaskDirective, TSecureConfiguration>, TaskDirective> method,
     TaskDirective directive = null
 )
 {
     return(this.StartRecurringBackgroundOperation <TaskDirective>
            (
                name,
                interval,
                method,
                directive
            ));
 }
Пример #5
0
 /// <summary>
 /// Runs the operation at once or immediately after the current run is finished.
 /// </summary>
 /// <param name="backgroundOperationName">The name of the background operation that should be invoked when this job is run.</param>
 /// <param name="runAt">If specified, schedules an execution at the provided time.  Otherwise schedules a call immediately.</param>
 /// <param name="directive">The directive - if any - to pass to the job.</param>
 /// <param name="vault">The vault reference to add the task.  Set to a transactional vault to only run the task if the transaction completes.</param>
 /// <remarks>Does not remove any scheduled executions.  Use <see cref="StopRunningAtIntervals"/>.</remarks>
 public void RunOnce
 (
     string backgroundOperationName,
     DateTime?runAt          = null,
     TaskDirective directive = null,
     Vault vault             = null
 )
 {
     // Use the other overload.
     this.RunOnce <TaskDirective>
     (
         backgroundOperationName,
         runAt,
         directive,
         vault
     );
 }
        /// <summary>
        /// Creates a <see cref="DashboardTable"/> containing information about the executions
        /// detailed in <paramref name="applicationTasks"/>.
        /// </summary>
        /// <param name="applicationTasks">The previous executions.</param>
        /// <returns>The table.</returns>
        public static IDashboardContent AsDashboardContent <TDirective>
        (
            this IEnumerable <TaskInfo <TDirective> > applicationTasks,
            int maximumRowsToShow = 40
        )
            where TDirective : TaskDirective
        {
            // Sanity.
            if (null == applicationTasks || false == applicationTasks.Any())
            {
                return(null);
            }
            var list = applicationTasks
                       .OrderByDescending(e => e.LatestActivity)
                       .ToList();

            // Create the table and header row.
            DashboardTable table = new DashboardTable();
            {
                var header = table.AddRow(DashboardTableRowType.Header);
                header.AddCells
                (
                    new DashboardCustomContent("Task"),
                    new DashboardCustomContent("Scheduled"),
                    new DashboardCustomContent("Duration"),
                    new DashboardCustomContent("Details")
                );
            }

            List <TaskInfo <TDirective> > executionsToShow;
            bool isFiltered = false;

            if (list.Count <= maximumRowsToShow)
            {
                executionsToShow = list;
            }
            else
            {
                isFiltered = true;

                // Show the latest 20 errors, then the rest filled with non-errors.
                executionsToShow = new List <TaskInfo <TDirective> >
                                   (
                    list
                    .Where(e => e.State == MFTaskState.MFTaskStateFailed)
                    .Take(20)
                    .Union(list.Where(e => e.State != MFTaskState.MFTaskStateFailed).Take(maximumRowsToShow - 20))
                                   );
            }

            // Add a row for each execution to show.
            foreach (var execution in executionsToShow)
            {
                TaskDirective internalDirective = execution.Directive;
                {
                    if (internalDirective is BackgroundOperationTaskDirective bgtd)
                    {
                        internalDirective = bgtd.GetParsedInternalDirective();
                    }
                }
                var directive   = internalDirective as ITaskDirectiveWithDisplayName;
                var displayName = string.IsNullOrWhiteSpace(directive?.DisplayName)
                                        ? execution.TaskId
                                        : directive.DisplayName;
                var             activation = execution.ActivationTime;
                TaskInformation taskInfo   = null == execution.Status?.Data
                                        ? new TaskInformation()
                                        : new TaskInformation(execution.Status.Data);

                // Create the content for the scheduled column (including icon).
                var taskInfoCell  = new DashboardCustomContentEx(System.Security.SecurityElement.Escape(displayName));
                var scheduledCell = new DashboardCustomContentEx
                                    (
                    activation.ToTimeOffset
                    (
                        // If we are waiting for it to start then highlight that.
                        execution.State == MFilesAPI.MFTaskState.MFTaskStateWaiting
                                                                ? FormattingExtensionMethods.DateTimeRepresentationOf.NextRun
                                                                : FormattingExtensionMethods.DateTimeRepresentationOf.LastRun
                    )
                                    );

                // Copy data from the execution if needed.
                taskInfo.Started            = taskInfo.Started ?? execution.ActivationTime;
                taskInfo.LastActivity       = taskInfo.LastActivity ?? execution.Status?.EndedAt ?? execution.Status?.LastUpdatedAt ?? DateTime.UtcNow;
                taskInfo.StatusDetails      = taskInfo.StatusDetails ?? execution.Status?.Details;
                taskInfo.PercentageComplete = taskInfo.PercentageComplete ?? execution.Status?.PercentComplete;
                if (taskInfo.CurrentTaskState != execution.State)
                {
                    taskInfo.CurrentTaskState = execution.State;
                }
                var removeLineBreaks = false;                 // By default show the full text as sent.
                if (taskInfo.CurrentTaskState == MFTaskState.MFTaskStateFailed)
                {
                    taskInfo.StatusDetails = execution.Status?.ErrorMessage ?? taskInfo.StatusDetails;
                    removeLineBreaks       = true;               // Exceptions are LONG, so format them.
                }

                // Add a row for this execution.
                var row = table.AddRow();

                // Set the row title.
                var rowTitle = "";
                switch (execution.State)
                {
                case MFilesAPI.MFTaskState.MFTaskStateWaiting:
                    taskInfoCell.Icon = "Resources/Waiting.png";
                    rowTitle          = $"Waiting.  Will start at approximately {activation.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")}.";
                    break;

                case MFilesAPI.MFTaskState.MFTaskStateInProgress:
                    rowTitle = "Running.";
                    if ((taskInfo?.Started.HasValue) ?? false)
                    {
                        rowTitle += $" Started at approximately {taskInfo.Started.Value.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")} server-time (taken {taskInfo.GetElapsedTime().ToDisplayString()} so far).";
                    }
                    taskInfoCell.Icon = "Resources/Running.png";
                    break;

                case MFilesAPI.MFTaskState.MFTaskStateFailed:
                    rowTitle = "Failed.";
                    if ((taskInfo?.Started.HasValue) ?? false)
                    {
                        rowTitle += $" Started at approximately {taskInfo.Started.Value.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")} server-time (took {taskInfo.GetElapsedTime().ToDisplayString()}).";
                    }
                    taskInfoCell.Icon = "Resources/Failed.png";
                    break;

                case MFilesAPI.MFTaskState.MFTaskStateCompleted:
                    rowTitle = "Completed.";
                    if ((taskInfo?.Started.HasValue) ?? false)
                    {
                        rowTitle += $" Started at approximately {taskInfo.Started.Value.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")} server-time (took {taskInfo.GetElapsedTime().ToDisplayString()}).";
                    }
                    taskInfoCell.Icon = "Resources/Completed.png";
                    break;

                default:
                    break;
                }
                row.Attributes.Add("title", rowTitle);

                // Add the cells to the row.
                row.AddCells
                (
                    taskInfoCell,
                    scheduledCell,
                    new DashboardCustomContent(execution.State == MFilesAPI.MFTaskState.MFTaskStateWaiting ? "" : taskInfo?.GetElapsedTime().ToDisplayString()),
                    taskInfo?.AsDashboardContent(removeLineBreaks)
                );

                // First three cells should be as small as possible.
                row.Cells[0].Styles.AddOrUpdate("width", "1%");
                row.Cells[0].Styles.AddOrUpdate("white-space", "nowrap");
                row.Cells[1].Styles.AddOrUpdate("width", "1%");
                row.Cells[1].Styles.AddOrUpdate("white-space", "nowrap");
                row.Cells[2].Styles.AddOrUpdate("width", "1%");
                row.Cells[2].Styles.AddOrUpdate("white-space", "nowrap");

                // Last cell should have as much space as possible.
                row.Cells[3].Styles.AddOrUpdate("width", "100%");
            }

            // Create an overview of the statuses.
            var data = list.GroupBy(e => e.State).ToDictionary(e => e.Key, e => e.Count());

            var overview = new DashboardTable();

            {
                // Remove all styles - we only are using this for layout.
                overview.Styles.Clear();
                overview.Styles.AddOrUpdate("width", "100%");

                // Add a single row.
                var row = overview.AddRow();

                // The first cell contains text if this table is filtered, or is empty otherwise.
                var cell1 = row.AddCell();
                if (isFiltered)
                {
                    cell1.InnerContent = new DashboardCustomContentEx($"<p style='font-size: 12px'><em>This table shows only {maximumRowsToShow} of {list.Count} tasks.</em></p>");
                }

                // The second cell contains the totals.
                var cell2 = row.AddCell(new DashboardCustomContentEx
                                        (
                                            "<span>Totals: </span>"
                                            + $"<span title='{(data.ContainsKey(MFTaskState.MFTaskStateWaiting) ? data[MFTaskState.MFTaskStateWaiting] : 0)} awaiting processing' style=\"display: inline-block; margin: 0px 2px; background-image: url({DashboardHelpersEx.ImageFileToDataUri("Resources/Waiting.png")}); background-repeat: no-repeat; background-position: 0 center; padding-left: 20px\">{(data.ContainsKey(MFTaskState.MFTaskStateWaiting) ? data[MFTaskState.MFTaskStateWaiting] : 0)}</span>"
                                            + $"<span title='{(data.ContainsKey(MFTaskState.MFTaskStateInProgress) ? data[MFTaskState.MFTaskStateInProgress] : 0)} running' style=\"display: inline-block; margin: 0px 2px; background-image: url({DashboardHelpersEx.ImageFileToDataUri("Resources/Running.png")}); background-repeat: no-repeat; background-position: 0 center; padding-left: 20px\">{(data.ContainsKey(MFTaskState.MFTaskStateInProgress) ? data[MFTaskState.MFTaskStateInProgress] : 0)}</span>"
                                            + $"<span title='{(data.ContainsKey(MFTaskState.MFTaskStateCompleted) ? data[MFTaskState.MFTaskStateCompleted] : 0)} completed' style=\"display: inline-block; margin: 0px 2px; background-image: url({DashboardHelpersEx.ImageFileToDataUri("Resources/Completed.png")}); background-repeat: no-repeat; background-position: 0 center; padding-left: 20px\">{(data.ContainsKey(MFTaskState.MFTaskStateCompleted) ? data[MFTaskState.MFTaskStateCompleted] : 0)}</span>"
                                            + $"<span title='{(data.ContainsKey(MFTaskState.MFTaskStateFailed) ? data[MFTaskState.MFTaskStateFailed] : 0)} failed' style=\"display: inline-block; margin: 0px 2px; background-image: url({DashboardHelpersEx.ImageFileToDataUri("Resources/Failed.png")}); background-repeat: no-repeat; background-position: 0 center; padding-left: 20px\">{(data.ContainsKey(MFTaskState.MFTaskStateFailed) ? data[MFTaskState.MFTaskStateFailed] : 0)}</span>"
                                        ));
                cell2.Styles.AddOrUpdate("text-align", "right");
            }

            // Return the content.
            return(new DashboardContentCollection()
            {
                table,
                overview
            });
        }
 /// <summary>
 /// Returns the directive of the <paramref name="taskInfo"/> a parsed/populated instance.
 /// </summary>
 /// <param name="applicationTaskInfo">The task to retrieve data for.</param>
 /// <returns>The directive, or null if no directive is found.</returns>
 public static TaskDirective GetDirective(this ApplicationTaskInfo applicationTaskInfo)
 {
     return(TaskDirective.Parse <BackgroundOperationTaskDirective>(applicationTaskInfo.TaskData)?.GetParsedInternalDirective());
 }