Watcher

Piotr Gankiewicz edited this page Jul 6, 2016 · 17 revisions

Watcher is responsible for performing the check on the given resource (e.g. API or database). There are many different watchers such as:

And each one of them does implement the same interface:

public interface IWatcher
{
    string Name { get; }
    Task<IWatcherCheckResult> ExecuteAsync();
}

IWatcher can be named whatever you'd like, basically, any name that is a meaningful one should be a good choice. You can also leave the name empty and the default one will be used, which is the "{Type} Watcher".

As for the IWatcherCheckResult interface, please navigate to the hooks page, and scroll down to the Consuming the watcher hooks data section, where you can read more about making use of this result type.

The invocation of the ExecuteAsync() method results in a single check on a selected resource (for example it may send the POST request to the API or run a SQL query on a database).
Although the IWatcher should be managed by the Warden instance, it is possible to create a new instance of the particular IWatcher and directly invoke the ExecuteAsync() to perform a check. The main difference is that you will have no access to any hooks and will have to manually handle the WatcherException if such occurs.

Configuration:

All of the watchers are configurable by using the specialized configuration classes. The convention for the watcher configuration class is {watcher_name}Configuration. For instance, the WebWatcher will have the configuration class called the WebWatcherConfiguration. Configuration classes follow the builder pattern and provide a fluent API. Once the configuration has been completed, it's required to invoke the Build() method, in order to get the instance of the configuration object.

Here's the example configuration of the API watcher, that will send a POST to the URL: http://my-api.com/users and ensure that the response does include the Location header.

var configuration = WebWatcherConfiguration
    .Create("http://my-api.com", HttpRequest.Post("users", new { name = "test" },
        headers: new Dictionary<string, string>
        {
            ["Authorization"] = "Token MyBase64EncodedString",
        }))
    .EnsureThat(response => response.Headers.Any(header => header.Key == "Location"))
    .Build();
var apiWatcher = WebWatcher.Create("My API watcher", configuration);

Watchers can be also configured by using the lambda - it is not required then (actually it is not possible) to invoke the Build() method, as it will be done under the hood. Configuring a watcher via the lambda expression may look like this:

In addition to that, all of the watchers can be added directly to the Warden by using the specialized extensions. An example of such configuration may look like this:

var wardenConfiguration = WardenConfiguration
    .Create()
    .AddWebWatcher("http://my-api.com", HttpRequest.Post("users", new {name = "test"},
        headers: new Dictionary<string, string>
        {
            ["Authorization"] = "Token MyBase64EncodedString",
        }), 
        cfg => cfg.EnsureThat(response => response.Headers.Any()),
        interval: TimeSpan.FromMilliseconds(500)
    )
    //Configure other watchers, hooks etc.

Please note that you may either use the lambda expression for configuring the watcher or pass the configuration instance directly. You may also configure the hooks by using another lambda expression available in the extension methods.

In order to learn more about configuring the hooks, please navigate to the hooks page. Hooks (callbacks) are a quite useful pattern, that will allow you to intercept all of the required events and data. Configuring the hooks for the watcher is done via the Warden instance.

Intervals:

Interval defines the period after which the Watcher will invoke the ExecuteAsync() method. To find out more about configuring the intervals please refer to this article.

Reusing watchers:

Even though it is not possible to configure a single watcher in a way that it behaves differently depending on some specific rules or does multiple checks at once (e.g. the single instance of a WebWatcher that would ping 10 different websites), it is recommended to create a multiple instances of the same watcher type, and then add all of them to the Warden instance to achieve such goal. For example, you can create 10 different instances (configured independently) of the WebWatcher, that will perform different tasks.