Esempio n. 1
0
        private void job_ExecuteCompleted(object sender, ReportExecutionEventArgs e)
        {
            #region logging

            Logger.TraceEvent(TraceEventType.Verbose, 0, "{0}: BEGIN ExecuteCompleted", e.Job.Id);

            #endregion

            try
            {
                try
                {
                    try
                    {
                        if (e.Job.State == ReportExecutionStateEnum.Failed)
                        {
                            //only "unexpected" errors should trigger recovery action
                            if (e.Job.ErrorCode.GetValueOrDefault(ReportExecutionErrorEnum.None) == ReportExecutionErrorEnum.None)
                            {
                                Interlocked.Increment(ref _consecutiveFailures);
                            }
                            Logger.TraceEvent(
                                TraceEventType.Error,
                                0,
                                "{0}: Report execution {1} failed. {2}.{3}{4}",
                                this.Name,
                                e.Job.Id,
                                e.Job.Error != null ? e.Job.Error.Message : string.Empty,
                                Environment.NewLine,
                                e.Job.Error != null ? e.Job.Error.ToString() : string.Empty);
                            if (_consecutiveFailures > this.MaxConsecutiveFailures)
                            {
                                _recoverySleep = true;
                            }
                        }
                        else
                        {
                            _consecutiveFailures         = 0;
                            this.CurrentRecoveryInterval = TimeSpan.FromSeconds(5);
                            _recoverySleep = false;
                        }
                    }
                    finally
                    {
                        //complete the execution
                        Logger.TraceEvent(TraceEventType.Information, 0, "{0}: Completing report execution {1}.", this.Name, e.Job.Id);
                        ReportExecution.CompleteExecution(e.Job);
                    }
                }

                #region exception handling

                catch (Exception ex)
                {
                    //TODO: more detailed exception handling
                    Logger.TraceEvent(TraceEventType.Error, 0, "{0}: {1}", ex.GetType(), ex.Message);
                    Logger.TraceEvent(TraceEventType.Information, 0, ex.ToString());
                    _recoverySleep = true;
                }

                #endregion
            }

            #region logging

            finally
            {
                Logger.TraceEvent(TraceEventType.Verbose, 0, "{0}: END ExecuteCompleted", e.Job.Id);
            }

            #endregion
        }
Esempio n. 2
0
        /// <summary>
        /// Does the work.
        /// </summary>
        protected override void DoWork()
        {
            #region validate configuration

            Debug.Assert(this.MaxConcurrentExecutions > 0);

            //TODO: validate configuration

            #endregion

            //use a semaphore to throttle the number of actively processing requests
            using (Semaphore semaphore = new Semaphore(MaxConcurrentExecutions, MaxConcurrentExecutions))
            {
                //need to wait on the semaphore and the wake event
                WaitHandle[] waitHandles = new WaitHandle[]
                {
                    semaphore,
                    base._wakeEvent
                };

                //start the main loop
                while (this.State == WorkerThreadState.Running)
                {
                    try
                    {
                        #region recovery

                        if (_recoverySleep)
                        {
                            Logger.TraceEvent(TraceEventType.Verbose, 0, "{0}: Waiting for recovery interval: {1}", this.Name, this.CurrentRecoveryInterval);
                            this.Sleep(this.CurrentRecoveryInterval);
                            _recoverySleep = false;
                            this.CurrentRecoveryInterval = this.CurrentRecoveryInterval.Add(this.CurrentRecoveryInterval);
                            if (this.State != WorkerThreadState.Running)
                            {
                                return;
                            }
                        }

                        #endregion

                        #region throttling

                        //implement throttling to control the number of concurrent work items queued on the Thread Pool
                        Logger.TraceEvent(TraceEventType.Verbose, 0, "{0}: Waiting on semaphore.", this.Name);
                        int eventIndex = WaitHandle.WaitAny(waitHandles);
                        if (this.State != WorkerThreadState.Running)
                        {
                            return;
                        }

                        #endregion

                        //get next report execution
                        ReportExecution job = null;
                        try
                        {
                            Logger.TraceEvent(TraceEventType.Information, 0, "{0}: Getting next scheduled report execution.", this.Name);
                            job = ReportExecution.GetNextJob();
                        }
                        catch
                        {
                            //on error, release semaphore
                            Logger.TraceEvent(TraceEventType.Verbose, 0, "{0}: Error getting report execution. Releasing semaphore.", this.Name);
                            semaphore.Release();
                            throw;
                        }

                        if (job == null)
                        {
                            //on no job, release semaphore and go to sleep
                            Logger.TraceEvent(TraceEventType.Information, 0, "{0}: No queued report executions.", this.Name);
                            Logger.TraceEvent(TraceEventType.Verbose, 0, "{0}: Releasing semaphore.", this.Name);
                            semaphore.Release();

                            _waitingForPollingInterval = true;
                            this.Sleep(this.PollingInterval);
                            _waitingForPollingInterval = false;
                        }
                        else
                        {
                            //handle message on ThreadPool
                            ThreadPool.QueueUserWorkItem(state =>
                            {
                                #region perform execution

                                try
                                {
                                    try
                                    {
                                        #region execute the report

                                        using (AutoResetEvent renderedEvent = new AutoResetEvent(false))
                                        {
                                            job.RenderCompleted += delegate(object sender, ReportExecutionEventArgs e)
                                            {
                                                #region handle render completed event

                                                Logger.TraceEvent(TraceEventType.Verbose, 0, "{0}: BEGIN RenderCompleted", e.Job.Id);
                                                try
                                                {
                                                    if (renderedEvent != null &&
                                                        !renderedEvent.SafeWaitHandle.IsClosed &&
                                                        !renderedEvent.SafeWaitHandle.IsInvalid)
                                                    {
                                                        renderedEvent.Set();
                                                    }
                                                }
                                                finally
                                                {
                                                    Logger.TraceEvent(TraceEventType.Verbose, 0, "{0}: END RenderCompleted", e.Job.Id);
                                                }

                                                #endregion
                                            };
                                            job.ExecuteCompleted += new EventHandler <ReportExecutionEventArgs>(job_ExecuteCompleted);

                                            //execute the report
                                            Logger.TraceEvent(TraceEventType.Information, 0, "{0}: Processing report execution {1}.", this.Name, job.Id);
                                            //job.Execute(this.ExecutionCredentials, this.ExecutionTimeout);
                                            var format = job.Format;
                                            job.ExecuteAsync(this.ExecutionCredentials, this.ExecutionTimeout, format);
                                            if (!renderedEvent.WaitOne(this.ExecutionTimeout, true))
                                            {
                                                Logger.TraceEvent(TraceEventType.Warning, 0, "{0}: Rendering timed out.", job.Id);

                                                //cancel the execution to ensure that the completed event never fires
                                                job.CancelExecute();

                                                job.Error     = new TimeoutException("The operation timed out waiting for rendering");
                                                job.ErrorCode = ReportExecutionErrorEnum.ExecutionTimeout;
                                                job.ErrorCount++;
                                                job.EndTime = DateTime.Now;
                                                job.State   = ReportExecutionStateEnum.Failed;

                                                TraceEventType eventType;

                                                switch (job.ErrorCode)
                                                {
                                                case ReportExecutionErrorEnum.InvalidReportParameter:
                                                    {
                                                        eventType = TraceEventType.Information;
                                                        break;
                                                    }

                                                default:
                                                    {
                                                        eventType = TraceEventType.Error;
                                                        break;
                                                    }
                                                }

                                                Logger.TraceEvent(
                                                    eventType,
                                                    0,
                                                    "{0}: Report execution {1} failed. {2}.{3}{4}",
                                                    this.Name,
                                                    job.Id,
                                                    job.Error != null ? job.Error.Message : string.Empty,
                                                    Environment.NewLine,
                                                    job.Error != null ? job.Error.ToString() : string.Empty);

                                                //complete the execution
                                                Logger.TraceEvent(TraceEventType.Information, 0, "{0}: Completing report execution {1}.", this.Name, job.Id);
                                                ReportExecution.CompleteExecution(job);
                                            }

                                            //At this point, the report has rendered and is downloading, so we can release
                                            //the semaphore to let another execution through. The ExecuteCompleted event
                                            //will fire when the report has finished downloading.
                                        }

                                        #endregion
                                    }
                                    catch (Exception ex)
                                    {
                                        //TODO: more detailed exception handling
                                        Logger.TraceEvent(TraceEventType.Error, 0, "{0}: {1}", ex.GetType(), ex.Message);
                                        Logger.TraceEvent(TraceEventType.Information, 0, ex.ToString());
                                        _recoverySleep = true;
                                    }
                                }
                                finally
                                {
                                    if (!semaphore.SafeWaitHandle.IsClosed)
                                    {
                                        Logger.TraceEvent(TraceEventType.Verbose, 0, "{0}: Releasing semaphore.", this.Name);
                                        semaphore.Release();
                                    }

                                    //TODO: review the following code. It was indirectly causing a SemaphoreFullException.
                                    ////wake-up the dispatcher thread if it is not in "recovery mode"
                                    ////this will prevent unnecessary waiting if the next execution time
                                    ////of the completed execution is already past
                                    //if (!_recoverySleep && _waitingForPollingInterval)
                                    //{
                                    //    this.WakeUp();
                                    //}
                                }

                                #endregion
                            });
                        }
                    }

                    #region exception handling

                    catch (Exception ex)
                    {
                        //TODO: only handle specific exceptions
                        Logger.TraceEvent(TraceEventType.Error, 0, "{0}: {1}", ex.GetType(), ex.Message);
                        Logger.TraceEvent(TraceEventType.Information, 0, ex.ToString());
                        _recoverySleep = true;
                    }

                    #endregion
                }
            }
        }
Esempio n. 3
0
        public static void CompleteExecution(ReportExecution execution)
        {
            #region logging

            execution.Log(TraceEventType.Verbose, "BEGIN CompleteExecution()");

            #endregion

            try
            {
                int executionId = int.Parse(execution.Id);
                if (execution.State != ReportExecutionStateEnum.Failed &&
                    execution.State != ReportExecutionStateEnum.Succeeded)
                {
                    throw new InvalidOperationException(string.Format("Execution {0} cannot be completed from its current state: {1}", executionId, execution.State));
                }
                if (execution.State == ReportExecutionStateEnum.Succeeded &&
                    execution.Data == null)
                {
                    throw new InvalidOperationException(string.Format("Execution {0} is in the 'Succeeded' state but it does not have any data", executionId));
                }

                using (ReportingDataContext content = new ReportingDataContext("Emdat.InVision.ReportContent"))
                    using (ReportingDataContext data = new ReportingDataContext())
                    {
                        //only update content if the data has been set
                        if (execution.State == ReportExecutionStateEnum.Succeeded &&
                            execution.Data != null)
                        {
                            #region logging

                            execution.Log(
                                TraceEventType.Verbose,
                                "Setting execution data (fileType={0}, dataLength={1})",
                                execution.FileType,
                                execution.Data != null ? execution.Data.Length : 0);

                            #endregion

                            try
                            {
                                //save the report data
                                var result = content.SetExecutionData(executionId, execution.FileType, execution.Data);
                                if (result < 1)
                                {
                                    throw new ApplicationException(string.Format("The execution data could not be set: {0}", executionId));
                                }
                            }
                            catch (Exception ex)
                            {
                                //TFS #13667: retry if there are problems saving the report content
                                execution.Log(TraceEventType.Warning, "Exception saving report content: {0}", ex.Message);
                                execution.Log(TraceEventType.Information, "{0}", ex);
                                execution.Error = ex;
                                execution.ErrorCount++;
                                data.SetExecutionRetry(
                                    executionId,
                                    execution.Name,
                                    execution.StartTime,
                                    execution.EndTime,
                                    execution.ErrorDescription,
                                    execution.ErrorCode.HasValue ? (int?)execution.ErrorCode.Value : null,
                                    execution.ErrorCount,
                                    execution.ScheduledRunTime,
                                    "SYSTEM",
                                    DateTime.Now);
                                return;
                            }
                        }

                        //only fail if success or the error code is set, otherwise, retry
                        if (execution.State == ReportExecutionStateEnum.Succeeded ||
                            execution.ErrorCode.HasValue)
                        {
                            string nextPrmsXml = ReportParametersHelper.GetParameterValuesXml(execution.NextScheduledRunParameters);

                            #region logging

                            execution.Log(
                                TraceEventType.Verbose,
                                "Setting execution status (name={0}, startTime={1:s}, endTime={2:s}, state={3}, errorCode={4}, errorCount={5}, usedHistory={6}, nextRun={7:s}, nextPrms={8}, report={9}, subscription={10}, format={11})",
                                execution.Name,
                                execution.StartTime,
                                execution.EndTime,
                                execution.State,
                                execution.ErrorCode,
                                execution.ErrorCount,
                                !string.IsNullOrEmpty(execution.HistoryId),
                                execution.NextScheduledRunTime,
                                nextPrmsXml,
                                execution.ReportId,
                                execution.SubscriptionId,
                                execution.FormatId);

                            #endregion

                            //update execution state
                            data.SetExecutionStatus(
                                reportExecutionID: executionId,
                                name: execution.Name,
                                startDate: execution.StartTime,
                                endDate: execution.EndTime,
                                reportExecutionStatusID: (int)execution.State,
                                errorDescription: execution.ErrorDescription,
                                errorCount: execution.ErrorCount,
                                reportExecutionErrorID: execution.ErrorCode.HasValue ? (int?)execution.ErrorCode.Value : null,
                                usedHistory: !string.IsNullOrEmpty(execution.HistoryId),
                                nextExecutionDate: execution.NextScheduledRunTime,
                                nextExecutionParameters: nextPrmsXml,
                                nextExecutionReportID: execution.ReportId,
                                nextExecutionSubscriptionID: execution.SubscriptionId,
                                nextExecutionFormatID: execution.FormatId,
                                modifiedUser: "******",
                                modifiedDate: DateTime.Now);
                        }
                        else
                        {
                            #region logging

                            execution.Log(
                                TraceEventType.Verbose,
                                "Setting execution retry (name={0}, startTime={1:s}, endTime={2:s}, state={3}, errorCode={4}, errorCount={5}, run={6})",
                                execution.Name,
                                execution.StartTime,
                                execution.EndTime,
                                execution.State,
                                execution.ErrorCode,
                                execution.ErrorCount,
                                execution.ScheduledRunTime);

                            #endregion

                            //retry
                            data.SetExecutionRetry(
                                executionId,
                                execution.Name,
                                execution.StartTime,
                                execution.EndTime,
                                execution.ErrorDescription,
                                execution.ErrorCode.HasValue ? (int?)execution.ErrorCode.Value : null,
                                execution.ErrorCount,
                                execution.ScheduledRunTime,
                                "SYSTEM",
                                DateTime.Now);
                        }
                    }
            }

            #region logging

            finally
            {
                execution.Log(TraceEventType.Verbose, "END CompleteExecution()");
            }

            #endregion
        }
Esempio n. 4
0
        public static ReportExecution GetNextJob()
        {
            ReportExecution exec = null;

            #region logging

            Logger.TraceEvent(
                TraceEventType.Verbose,
                0,
                "{0}: BEGIN GetNextJob()",
                System.Threading.Thread.CurrentThread.ManagedThreadId);

            #endregion

            try
            {
                using (ReportingDataContext data = new ReportingDataContext())
                {
                    //get the next execution from the queue
                    var execRow =
                        (from e in data.GetExecutionFromQueue()
                         where e.ScheduledStartDate.HasValue
                         select e).FirstOrDefault();

                    if (execRow == null)
                    {
                        return(null);
                    }

                    try
                    {
                        var format       = data.GetFormat(execRow.ReportFormatID).FirstOrDefault();
                        var report       = data.GetReport(execRow.ReportID, execRow.EnvironmentID).FirstOrDefault();
                        var subscription = data.GetSubscription(execRow.ReportSubscriptionID).FirstOrDefault();
                        exec = GetReportExecutionFromRow(execRow, format, report, subscription);
                    }
                    catch (Exception ex)
                    {
                        //WI #2889: mark the execution for retry on exception
                        data.SetExecutionRetry(
                            execRow.ReportExecutionID,
                            execRow.Name,
                            null,
                            null,
                            ex.ToString(),
                            null,
                            execRow.ErrorCount + 1,
                            execRow.ScheduledStartDate,
                            "SYSTEM",
                            DateTime.Now);

                        //re-throw exception
                        throw;
                    }
                }
            }

            #region logging

            finally
            {
                Logger.TraceEvent(
                    TraceEventType.Verbose,
                    0,
                    "{0}: END GetNextJob(id={1}, state={2}, run={3}, nextRun={4}, subscription={5}, reportId={6}, path={7}, formatId={8}, format={9})",
                    System.Threading.Thread.CurrentThread.ManagedThreadId,
                    exec != null ? exec.Id : null,
                    exec != null ? (ReportExecutionStateEnum?)exec.State : null,
                    exec != null ? exec.ScheduledRunTime : null,
                    exec != null ? exec.NextScheduledRunTime : null,
                    exec != null ? exec.SubscriptionId : null,
                    exec != null ? (int?)exec.ReportId : null,
                    exec != null ? exec.ReportPath : null,
                    exec != null ? (int?)exec.FormatId : null,
                    exec != null ? exec.Format : null);
            }

            #endregion

            return(exec);
        }
Esempio n. 5
0
 public ReportExecutionEventArgs(ReportExecution job)
     : base()
 {
     this.Job = job;
 }