# Monitor third-party systems with custom checks
External, third-party systems becoming unavailable might cause message-processing failures. The Particular Platform supports monitoring of third-party systems exposed as HTTP endpoints. This sample shows how to set up such monitoring using custom checks.
## Running the sample
Running the project will result in 3 console windows:
1. **3rdPartySystem**: Represents the third-party system by simulating an HTTP service running on `http://localhost:57789`. At startup, the custom check is returning success, but the state can be toggled between success and failure by pressing Enter.
1. **Monitor3rdParty**: The endpoint containing the custom check. The success or failure of the third-party system is continuously written to the console.
1. **PlatformLauncher**: Runs an in-process version of ServiceControl and ServicePulse. When the ServiceControl instance is ready, a browser window will be launched displaying the Custom Checks view in ServicePulse.
Try toggling the status of the third-party system by pressing Enter in the **3rdPartySystem** window, and watch the change in the output of the **Monitor3rdParty** window.
The status of the custom check is also reported to ServiceControl, and can be viewed in ServicePulse. In the browser window, navigate to the ServicePulse **Custom Checks** page to see the status change from success to error. The ServicePulse **Dashboard** page provides the overall status of custom checks.
## The custom check
The monitoring logic implements a `PeriodicCheck` which calls a configured URI whenever the specified interval elapses. When the third-party system doesn't respond in a timely fashion, a `CheckResult.Failed` event is sent to ServiceControl.
```cs
sealed class ThirdPartyMonitor(ILogger logger)
: CustomCheck(
id: $"Monitor {Url}",
category: "Monitor 3rd Party ",
repeatAfter: TimeSpan.FromSeconds(10)
)
{
const string Url = "http://localhost:57789";
static readonly HttpClient Client = new() // Normally configured in host DI config
{
Timeout = TimeSpan.FromSeconds(3)
};
public override async Task PerformCheck(CancellationToken cancellationToken = default)
{
try
{
using var response = await Client.GetAsync(Url, cancellationToken);
if (response.IsSuccessStatusCode)
{
logger.LogInformation("Succeeded in contacting {Url}", Url);
return CheckResult.Pass;
}
logger.LogWarning("Failed to contact 3rd party. HttpStatusCode: {ResponseStatusCode}", response.StatusCode);
return CheckResult.Failed($"Failed to contact 3rd party. HttpStatusCode: {response.StatusCode}");
}
catch (Exception exception)
{
logger.LogWarning(exception, "Failed to contact 3rd party");
return CheckResult.Failed($"Failed to contact 3rd party. Error: {exception.Message}");
}
}
}
```