CREATE TABLE LeaderElection (
Id INT PRIMARY KEY IDENTITY,
HostName NVARCHAR(255) NOT NULL,
Port INT NOT NULL,
IsLeader BIT NOT NULL,
LastHeartbeat DATETIME NOT NULL
);
public class LeaderElection { public int Id { get; set; } public string HostName { get; set; } public int Port { get; set; } public bool IsLeader { get; set; } public DateTime LastHeartbeat { get; set; } }
public class LeaderElectionService
{
private readonly ApplicationDbContext _dbContext;
private readonly IHttpContextAccessor _httpContextAccessor;
private string _hostName;
private int _port;
private Timer _timer;
public LeaderElectionService(ApplicationDbContext dbContext, IHttpContextAccessor httpContextAccessor)
{
_dbContext = dbContext;
_httpContextAccessor = httpContextAccessor;
// Retrieve the host and port from the HTTP context or environment
InitializeHostAndPort();
}
private void InitializeHostAndPort()
{
// Retrieve host and port from the current HTTP context, if available
if (_httpContextAccessor.HttpContext != null)
{
var request = _httpContextAccessor.HttpContext.Request;
_hostName = request.Host.Host;
_port = request.Host.Port ?? 80; // Default to 80 if port is not specified
}
else
{
// Use fallback, such as environment variables or predefined config
_hostName = Environment.GetEnvironmentVariable("HOSTNAME") ?? "localhost";
_port = int.TryParse(Environment.GetEnvironmentVariable("PORT"), out int port) ? port : 5000;
}
}
public void Start()
{
_timer = new Timer(CheckLeadership, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
}
private void CheckLeadership(object state)
{
using (var transaction = _dbContext.Database.BeginTransaction())
{
var existingLeader = _dbContext.LeaderElections
.OrderByDescending(le => le.LastHeartbeat)
.FirstOrDefault(le => le.IsLeader);
if (existingLeader != null && (DateTime.UtcNow - existingLeader.LastHeartbeat).TotalSeconds < 10)
{
// Existing leader is still alive
if (existingLeader.HostName == _hostName && existingLeader.Port == _port)
{
// Update own heartbeat
existingLeader.LastHeartbeat = DateTime.UtcNow;
_dbContext.SaveChanges();
}
}
else
{
// No leader or leader has failed, try to become leader
var self = _dbContext.LeaderElections
.FirstOrDefault(le => le.HostName == _hostName && le.Port == _port);
if (self == null)
{
self = new LeaderElection
{
HostName = _hostName,
Port = _port,
IsLeader = true,
LastHeartbeat = DateTime.UtcNow
};
_dbContext.LeaderElections.Add(self);
}
else
{
self.IsLeader = true;
self.LastHeartbeat = DateTime.UtcNow;
}
_dbContext.SaveChanges();
}
transaction.Commit();
}
}
}
No comments:
Post a Comment