protected override void Notify(WorkerResult result) { SmtpMail.SmtpServer = SmtpServer; SmtpMail.Send(From, To, string.Format(Subject, result.ShortMessage), string.Format(Body, result.DetailedMessage)); }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// <summary> /// This method is is called when a scheduler determines that a job should be run.</summary> protected void Scheduler_OnScheduled(object sender, EventArgs args) { // make sure the job really has a worker if ( _worker != null ) { // this will store the worker's result WorkerResult result; // log the that the worker is running Trace.WriteLineIf(_jobSwitch.TraceVerbose, string.Format("{0:yyyy-MM-dd HH:mm:ss.ffff}\t{1}\tJob\t{2}\t{3}", DateTime.Now, AppDomain.GetCurrentThreadId(), "Worker", _worker.Description )); try { // run the worker! result = _worker.Run(); } catch (Exception e) { // if there was an exception trying to run the worker, then store that as the result result = new WorkerResult(AgentWorker.STATE_EXCEPTION, WorkerResultStatus.Exception, _worker.Description, string.Format(_worker.MessageException, DateTime.Now, e.Message), e ); } // Check to see if the result is an ignorable exception and if so when the worker should be rescheduled long retryDelayMilliseconds = 0; bool ignoreException = CheckForIgnorableException(result, ref retryDelayMilliseconds); // log the worker result Trace.WriteLineIf(_jobSwitch.TraceInfo, string.Format("{0:yyyy-MM-dd HH:mm:ss.ffff}\t{1}\tJob\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}", DateTime.Now, AppDomain.GetCurrentThreadId(), "Worker", _worker.Description, result.Status, (result.WorkerException == null) ? null : result.WorkerException.GetType(), (result.WorkerException == null) ? string.Empty : result.WorkerException.Message, ignoreException ? "IGNORE" : "NOTIFY" )); // determine how to proceed if ( ignoreException ) { // this was an exception that can be ignored, but we need to reschedule // the job with the scheduler that called us AgentScheduler scheduler = sender as AgentScheduler; if ( scheduler != null ) { TimeSpan retryDelayTimeSpan = new TimeSpan( TimeSpan.TicksPerMillisecond * retryDelayMilliseconds ); scheduler.RequestRescheduling( retryDelayTimeSpan ); } } else { // this is a normal worker result that is not ignored, so let's request notification foreach(AgentNotifier notifier in _notifiers) notifier.RequestNotification(result); } // store this result as the previous result _lastWorkerResult = result; }//if }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// <summary> /// Check's to see if the worker's result is an exception that can be ignored and the work rescheduled.</summary> protected virtual bool CheckForIgnorableException(WorkerResult result, ref long retryDelayMilliseconds) { // assume the worst bool ignorableException = true; // was there an exception? if ( result.Status != WorkerResultStatus.Exception ) { // no exception - therefore not an ignorable exception ignorableException = false; } else { // there was an exception - search through the job's ignorable exeptions for a match AgentIgnorableException exception = _ignorableExceptions.Find(result.WorkerException); // if there was no match, search through the global ignorable exceptions for a match if ( exception == null ) exception = _globalIgnorableExceptions.Find(result.WorkerException); // was this an ignorable exception? if ( exception == null ) { // if there was still no match, then it was not an ignorable exception ignorableException = false; } else { // IGNORABLE EXCEPTION // return the number of milliseconds to wait before re-trying after this exception retryDelayMilliseconds = exception.RetryDelayMilliseconds; // is this the same as the previous ignorable exception? if ( lastIgnorableExceptionName != exception.Name ) { // it is not the same - reset the previous name to this one and the count to 0 lastIgnorableExceptionName = exception.Name; lastIgnorableExceptionCount = 0; } // increment the consecutive specific ignorable exception count lastIgnorableExceptionCount++; // increment the consecutive total ignorable exception count totalConsecutiveIgnorableExceptionsCount++; // see if the consecutive counts exceeds the limits if ( lastIgnorableExceptionCount > exception.MaximumConsecutiveIgnoreCount ) { // specific one does exceed the limit, so it is no longer ignorable ignorableException = false; } else if ( totalConsecutiveIgnorableExceptionsCount > MaximumConsecutiveExceptionIgnoreCount ) { // total count exceeds the limit, so it is no longer ignorable ignorableException = false; } } // exception is ignorable } // result is an exception // is this an ignorable exception? if ( !ignorableException ) { // it is NOT an ignorable exeption so reset the counts and previous exception name totalConsecutiveIgnorableExceptionsCount = 0; lastIgnorableExceptionCount = 0; lastIgnorableExceptionName = string.Empty; } // return the final status of whether this was ignorable or not return ignorableException; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// <summary> /// This method must be implemented by the derived class and must /// do the actual notification.</summary> protected abstract void Notify(WorkerResult result);
/// <summary> /// This method is called when RequestNotify determines that notification should take place.</summary> protected void FireNotify(WorkerResult result) { try { Notify(result); if ( NotifierSwitch.TraceVerbose ) System.Diagnostics.Trace.WriteLine(string.Format("{0:yyyy-MM-dd HH:mm:ss.ffff}\t{1}\tNotifier\t{2}\t{3}\t{4}", DateTime.Now, AppDomain.GetCurrentThreadId(), "Notify()", this.GetType(), "OK" )); } catch (Exception e) { if ( NotifierSwitch.TraceError ) System.Diagnostics.Trace.WriteLine(string.Format("{0:yyyy-MM-dd HH:mm:ss.ffff}\t{1}\tNotifier\t{2}\t{3}\t{4}", DateTime.Now, AppDomain.GetCurrentThreadId(), "Notify()", this.GetType(), e.Message )); } }
/// <summary> /// This method is called by the job after the worker is run. /// The code should determine, based on the worker result, /// whether or not a notification should be sent.</summary> public void RequestNotification(WorkerResult result) { bool notify = false; // If the status warrants notification and no notification was sent for this status in the allotted time period, send it. if ( ShouldNotify(result.Status) && (DateTime.Now.Subtract(LastNotified(result.State)) >= MaxNotificationFrequency) ) notify = true; // If the PREVIOUS status warrants notification and the state has changed, send this notification too. else if ( (_lastWorkerResult != null) && ShouldNotify(_lastWorkerResult.Status) && (result.State != _lastWorkerResult.State) ) notify = true; // no matter what, do not exceed this many notifications in the specified period if ( CheckPeriodNotificationsCount() >= MaxNotificationCountInPeriod ) notify = false; // NOTIFY? if ( notify ) { _lastWorkerResult = result; _lastNotifiedByState[result.State] = DateTime.Now; _notificationHistory.Add(DateTime.Now); FireNotify(result); } }