Commit d8d9e40e authored by Dan Gershony's avatar Dan Gershony

Adding a hearbeat that if enabled will shutdown the node after a trashold

parent 6bb09403
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
using Breeze.Api.Models;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Stratis.Bitcoin;
using Stratis.Bitcoin.Builder;
using Stratis.Bitcoin.Builder.Feature;
using Stratis.Bitcoin.Logging;
using Stratis.Bitcoin.Utilities;
namespace Breeze.Api
{
......@@ -14,31 +18,77 @@ namespace Breeze.Api
{
private readonly IFullNodeBuilder fullNodeBuilder;
private readonly FullNode fullNode;
private readonly ApiFeatureOptions apiFeatureOptions;
private readonly IAsyncLoopFactory asyncLoopFactory;
public ApiFeature(IFullNodeBuilder fullNodeBuilder, FullNode fullNode)
public ApiFeature(IFullNodeBuilder fullNodeBuilder, FullNode fullNode, ApiFeatureOptions apiFeatureOptions, IAsyncLoopFactory asyncLoopFactory)
{
this.fullNodeBuilder = fullNodeBuilder;
this.fullNode = fullNode;
this.apiFeatureOptions = apiFeatureOptions;
this.asyncLoopFactory = asyncLoopFactory;
}
public override void Start()
{
Logs.FullNode.LogInformation($"Api starting on url {this.fullNode.Settings.ApiUri}");
Program.Initialize(this.fullNodeBuilder.Services, this.fullNode);
this.TryStartHeartbeat();
}
/// <summary>
/// A heartbeat monitor that when enabled will shutdown
/// the node if no external beat was made during the trashold
/// </summary>
public void TryStartHeartbeat()
{
if (this.apiFeatureOptions.HeartbeatMonitor?.HeartbeatInterval.TotalSeconds > 0)
{
this.asyncLoopFactory.Run("ApiFeature.MonitorHeartbeat", token =>
{
// shortened for redability
var monitor = this.apiFeatureOptions.HeartbeatMonitor;
// check the trashold to trigger a shutdown
if (monitor.LastBeat.Add(monitor.HeartbeatInterval) < DateTime.UtcNow)
this.fullNode.Stop();
return Task.CompletedTask;
},
this.fullNode.GlobalCancellation.Cancellation.Token,
repeatEvery: this.apiFeatureOptions.HeartbeatMonitor?.HeartbeatInterval,
startAfter: TimeSpans.Minute);
}
}
}
public static class ApiFeatureExtension
public class ApiFeatureOptions
{
public HeartbeatMonitor HeartbeatMonitor { get; set; }
public void Heartbeat(TimeSpan timeSpan)
{
this.HeartbeatMonitor = new HeartbeatMonitor {HeartbeatInterval = timeSpan};
}
}
public static class ApiFeatureExtension
{
public static IFullNodeBuilder UseApi(this IFullNodeBuilder fullNodeBuilder)
public static IFullNodeBuilder UseApi(this IFullNodeBuilder fullNodeBuilder, Action<ApiFeatureOptions> optionsAction = null)
{
fullNodeBuilder.ConfigureFeature(features =>
// TODO: move the options in to the feature builder
var options = new ApiFeatureOptions();
optionsAction?.Invoke(options);
fullNodeBuilder.ConfigureFeature(features =>
{
features
.AddFeature<ApiFeature>()
.FeatureServices(services =>
{
services.AddSingleton(fullNodeBuilder);
services.AddSingleton(options);
});
});
......
using System.ComponentModel.DataAnnotations;
using System;
using System.ComponentModel.DataAnnotations;
using Breeze.Api.Models;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using NBitcoin;
......@@ -11,10 +13,12 @@ namespace Breeze.Api.Controllers
public class NodeController : Controller
{
private readonly IFullNode fullNode;
private readonly ApiFeatureOptions apiFeatureOptions;
public NodeController(IFullNode fullNode)
public NodeController(IFullNode fullNode, ApiFeatureOptions apiFeatureOptions)
{
this.fullNode = fullNode;
this.apiFeatureOptions = apiFeatureOptions;
}
/// <summary>
......@@ -41,6 +45,21 @@ namespace Breeze.Api.Controllers
return this.Ok();
}
}
/// <summary>
/// Set the hearbeat flag.
/// </summary>
/// <returns></returns>
[HttpPost]
[Route("heartbeat")]
public IActionResult Heartbeat()
{
if (this.apiFeatureOptions.HeartbeatMonitor == null)
return new ObjectResult("Heartbeat Disabled") {StatusCode = 405}; // (405) Method Not Allowed
this.apiFeatureOptions.HeartbeatMonitor.LastBeat = DateTime.UtcNow;
return this.Ok();
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Breeze.Api.Models
{
public class HeartbeatMonitor
{
public DateTime LastBeat { get; set; }
public TimeSpan HeartbeatInterval { get; set; }
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment