Hooks

Piotr Gankiewicz edited this page Apr 5, 2016 · 18 revisions

Hooks are basically callbacks that are being invoked by the specific actions, both by the Warden and the watchers. By using the hooks you are able to collect a lot of informative data and get instantly notified e.g. when an error occurs so that you may, for example, notify the system administrator that some particular resource has just become unavailable or collect the custom metrics.

Watcher hooks list:

  • OnStart() - invoked when the ExecuteAsync() is about to start, returns the IWatcherCheck.
  • OnStartAsync() - invoked when the ExecuteAsync() is about to start, returns the IWatcherCheck.
  • OnSuccess() - invoked when the ExecuteAsync() succeeded, returns the IWardenCheckResult.
  • OnSuccessAsync() - invoked when the ExecuteAsync() succeeded, returns the IWardenCheckResult.
  • OnFirstSuccess()- invoked when the ExecuteAsync() succeeded for the first time after the previous check didn't succeed, returns the IWardenCheckResult.
  • OnFirstSuccessAsync()- invoked when the ExecuteAsync() succeeded for the first time after the previous check didn't succeed, returns the IWardenCheckResult.
  • OnFailure() - invoked when the ExecuteAsync() failed, returns the IWardenCheckResult.
  • OnFailureAsync()- invoked when the ExecuteAsync() failed, returns the IWardenCheckResult.
  • OnFirstFailure() - invoked when the ExecuteAsync() failed for the first time after the previous check did succeed, returns the IWardenCheckResult.
  • OnFirstFailureAsync()- invoked when the ExecuteAsync() failed for the first time after the previous check did succeed, returns the IWardenCheckResult.
  • OnCompleted() - invoked when the ExecuteAsync() completed, regardless it's succeeded or not, returns the IWardenCheckResult.
  • OnCompletedAsync()- invoked when the ExecuteAsync() completed, regardless it's succeeded or not, returns the IWardenCheckResult.
  • OnError() - invoked when the ExecuteAsync() threw an exception, returns the Exception.
  • OnErrorAsync()- invoked when the ExecuteAsync() threw an exception, returns the Exception.
  • OnFirstError() - invoked when the ExecuteAsync() threw an exception for the first time after the previous check either succeeded or not, returns the Exception.
  • OnFirstErrorAsync() - invoked when the ExecuteAsync() threw an exception for the first time after the previous check either succeeded or not, returns the Exception.

Watcher hooks configuration

Configuring hooks for the watchers can be done in two ways - you can set the custom hooks for the specific watcher and/or the global, default hooks that will be common for all of the watchers. On top of that, you may use the aggregated hooks that will be called once the iteration has completed and will contain all of the watcher results stored in a collection (the only hooks that are not available here are OnStart() and OnStartAsync()).

Please note that if you specify both, the global hooks and custom hooks e.g. OnStart() common for all of the watchers, and OnStart() as a separate configuration for a specific watcher, this particular watcher will have two OnStart() hooks defined that will be invoked respectively.

Configuring the watcher hooks is done via the WardenConfiguration:

var configuration = WardenConfiguration
    .Create()
    .AddWatcher(apiWatcher)
    .AddWatcher(mssqlWatcher)
    .AddWatcher(mongoDbWatcher)
    .AddWatcher(websiteWatcher, hooks =>
    {
        hooks.OnStartAsync(check => WebsiteHookOnStartAsync(check));
        hooks.OnFailureAsync(result => WebsiteHookOnFailureAsync(result));
        hooks.OnSuccessAsync(result => WebsiteHookOnSuccessAsync(result));
        hooks.OnCompletedAsync(result => WebsiteHookOnCompletedAsync(result));
    })
    .SetGlobalWatcherHooks(hooks =>
    {
        hooks.OnStart(check => GlobalHookOnStart(check));
        hooks.OnFailure(result => GlobalHookOnFailure(result));
        hooks.OnSuccess(result => GlobalHookOnSuccess(result));
        hooks.OnCompleted(result => GlobalHookOnCompleted(result));
        hooks.OnError(exception => Logger.Error(exception));
    })
    .SetAggregatedWatcherHooks(hooks =>
    {
        hooks.OnFirstSuccessAsync(results => AggregatedHookOnFirstSuccessAsync(check));
        hooks.OnFirstSuccessAsync(results => AggregatedHookOnFirstFailureAsync(result));
    })
    .Build();

In the example above, the website watcher will have it's own specific hooks, but also will inherit the common hooks configured with the SetGlobalWatcherHooks(). The aggregated hooks will be called once the iteration has completed and will containt all of the watcher results stored in a collection.

Hooks and integrations

Each hook configuration via the lambda expression contains the additional overload that has the integrations provider. To find out more about integrations, please click here. An example of using the SendGrid integration while configuring the aggregated hooks may look like this:

.SetAggregatedWatcherHooks((hooks, integrations) =>
{
    hooks.OnFirstFailureAsync(results => 
            integrations.SendGrid().SendEmailAsync("Monitoring errors have occured."))
         .OnFirstSuccessAsync(results => 
            integrations.SendGrid().SendEmailAsync("Everything is up and running again!"));
})  

Consuming the watcher hooks data

Let's start with the definition of the interfaces that are being used by the watcher hooks.

public interface IWatcherCheck
{
    string WatcherName { get; }
    Type WatcherType { get; }
}

IWatcherCheck contains the specified watcher name and it's type. Used only by the OnStart() and OnStartAsync() which allows to identify which watcher is about to perform the check.

public interface IValidatable
{
    bool IsValid { get; }
}

IValidatable is a common interface with a single property determing the success of an operation.

public interface ITimestampable
{
    DateTime StartedAt { get; }
    DateTime CompletedAt { get; }
    TimeSpan ExecutionTime { get; }
}

ITimestampable is a common interface containing the dates and times of the watcher check execution. By default the UTC format is being used, but it's possible to configure the custom DateTime provider.

public interface IWatcherCheckResult : IValidatable, IWatcherCheck
{
    string Description { get; }
}

IWatcherCheckResult holds the information about the watcher check result. That interface is implemented by specific watchers, which allows passing the custom data. It's a part of the interface defined below, which is used by most of the watcher hooks. When you receive an instance of this object, you may cast it to the watcher's specific type such as the WebWatcherCheckResult, MsSqlWatcherCheckResult etc. - these types typically contain a much more useful data that is limited to the particular type of the watcher.

public interface IWardenCheckResult : IValidatable, ITimestampable
{
    IWatcherCheckResult WatcherCheckResult { get; }
    Exception Exception { get; }
}

IWardenCheckResult contains the specific IWatcherCheckResult type and also the dates and times at which the watcher check has been executed. If an exception occurred during the execution of the watcher check, it will be stored in the Exception property. This interface is used by most of the hooks, such as: OnSuccess(), OnSuccessAsync(), OnFirstSuccess(), OnFirstSuccessAsync(), OnFailure(), OnFailureAsync(), OnFirstFailure(), OnFirstFailureAsync(), OnCompleted() and OnCompletedAsync(). Please note that when a failure occurs, some of the specific informations included in the IWatcherCheckResult may not be available e.g. the HttpResponseMessage in the website watcher if there was a timeout while making a request to the given URL.

Remaining hooks: OnError(), OnErrorAsync(), OnFirstError() and OnFirstSuccessError() return a well known Exception.

Warden hooks list:

  • OnStart() - invoked when the StartAsync() is executed.
  • OnStartAsync() - invoked when the StartAsync() is executed.
  • OnPause() - invoked when the PauseAsync() is executed.
  • OnPauseAsync() - invoked when the StopAsync() is executed.
  • OnStop() - invoked when the StopAsync() is executed.
  • OnStopAsync() - invoked when the PauseAsync() is executed.
  • OnIterationStart() - invoked when the ExecuteAsync() is started by the IIterationProcessor, returns the long that represents the number of the current iteration.
  • OnIterationStartAsync() - invoked when the ExecuteAsync() is started by the IIterationProcessor, returns the long that represents the number of the current iteration. IWardenIteration.
  • OnIterationCompleted() - invoked when the ExecuteAsync() has completed, returns the IWardenIteration.
  • OnIterationCompletedAsync() - invoked when the ExecuteAsync() has completed, returns the IWardenIteration.
  • OnError() - invoked when the ExecuteAsync() responsible for processing the iteration threw an exception, returns the Exception.
  • OnErrorAsync() - invoked when the ExecuteAsync() responsible for processing the iteration threw an exception, returns the Exception.

Warden hooks configuration

Configuring hooks for the Warden can be done with the WardenConfiguration, by using the SetHooks().

var configuration = WardenConfiguration
    .Create()
    .SetHooks(hooks =>
    {
        hooks.OnError(exception => Logger.Error(exception));
        hooks.OnIterationCompleted(iteration => OnIterationCompleted(iteration));
    })
    ///Configure watchers etc.
    .Build();

Consuming the Warden hooks data

Let's begin with the definition of the most important interface:

public interface IWardenIteration : IValidatable, ITimestampable
{
    long Ordinal { get; }
    IEnumerable<IWardenCheckResult> Results { get; }
}

IWardenIteration has the number (ordinal) of the executed iteration (e.g. 1,2,3 ... N) and the collection of the IWardenCheckResult. For example, let's say you have added 3 watchers this list will then contain 3 elements.
You may use that single hook to gather all of the watcher check results at once, validate if they are successful or not and then perform some action based on that information. This interface is used only by the OnIterationCompleted() and OnIterationCompletedAsync() hooks.

The following hooks do not return anything: OnStart(), OnStartAsync(), OnPause(), OnPauseAsync(), OnStop(), OnStopAsync().

Remaining hooks: OnError() and OnErrorAsync() return a well known Exception.