/// <summary> /// Am I Primary? /// </summary> /// <param name="info">ElectorInfo</param> /// <returns>True, if so</returns> public bool AmIPrimary(ElectorInfo info) { bool amI = false; ConnectionMultiplexer redis; IDatabase db; ITransaction trans; DateTime stamp = DateTime.UtcNow; ElectorInfo otherInfo; int expireMS = GetExpirationMilliseconds(); try { redis = ConnectionMultiplexer.Connect(this._config.RedisConnectionString()); redis.IncludeDetailInExceptions = true; db = redis.GetDatabase(); trans = db.CreateTransaction(); var text = db.StringGet(info.ApplicationName); if (string.IsNullOrWhiteSpace(text)) { otherInfo = info; } else { otherInfo = JsonConvert.DeserializeObject <ElectorInfo>(text); } if (otherInfo.UniqueInstanceId == info.UniqueInstanceId) { UpdateKey(db, info, stamp); amI = true; } else { var ts = stamp - otherInfo.LastCallUtc; var age = ts.TotalMilliseconds; if (age > expireMS) { UpdateKey(db, info, stamp); amI = true; } } trans.Execute(); } finally { db = null; trans = null; redis = null; } return(amI); }
/// <summary> /// /// </summary> /// <param name="applicationName"></param> /// <returns></returns> public bool ForceElection(string applicationName) { ConnectionMultiplexer redis; IDatabase db; ITransaction trans; try { redis = ConnectionMultiplexer.Connect(this._config.RedisConnectionString()); redis.IncludeDetailInExceptions = true; db = redis.GetDatabase(); trans = db.CreateTransaction(); DateTime stamp = DateTime.UtcNow.AddDays(-1); var info = new ElectorInfo() { LastCallUtc = stamp, ApplicationName = applicationName, UniqueInstanceId = NO_INSTANCE }; UpdateKey(db, info, stamp); trans.Execute(); } finally { db = null; trans = null; redis = null; } return(true); }
private void UpdateKey(IDatabase db, ElectorInfo info, DateTime stamp) { info.LastCallUtc = stamp; var text = JsonConvert.SerializeObject(info); db.KeyDelete(info.ApplicationName); db.StringSet(info.ApplicationName, text); }
public void ConCurr_1() { bool amIPrimary = false; RedisElectorProvider prov = new RedisElectorProvider(redisConfig); prov.SetExpirationMilliseconds(RedisElectorProvider.Recommended_ExpirationMilliseconds); DateTime stamp = DateTime.UtcNow; var agent1 = new ElectorInfo() { ApplicationName = ApplicationName, LastCallUtc = stamp, UniqueInstanceId = Guid.NewGuid().ToString() }; amIPrimary = prov.AmIPrimary(agent1); Assert.IsTrue(amIPrimary, "Agent 1"); var agent2 = new ElectorInfo() { ApplicationName = ApplicationName, LastCallUtc = stamp, UniqueInstanceId = Guid.NewGuid().ToString() }; amIPrimary = prov.AmIPrimary(agent2); Assert.IsFalse(amIPrimary, "Agent 2"); Thread.Sleep(RedisElectorProvider.Recommended_ExpirationMilliseconds + 1000); agent2.LastCallUtc = DateTime.UtcNow; amIPrimary = prov.AmIPrimary(agent2); Assert.IsTrue(amIPrimary, "Agent 2"); agent1.UpdateLastCallUtc(); amIPrimary = prov.AmIPrimary(agent1); Assert.IsFalse(amIPrimary, "Agent 1"); amIPrimary = prov.AmIPrimary(agent1); Assert.IsFalse(amIPrimary, "Agent 1"); amIPrimary = prov.AmIPrimary(agent2); Assert.IsTrue(amIPrimary, "Agent 2"); }
static int Main(string[] args) { AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; logger = LogFactoryHelper.CreateLogger <Program>(); string fallbackFilename = @"VCAP_Services.json"; if (args.Length > 0) { fallbackFilename = args[0]; } // Get Assembly Object, casting it to this class type var assembly = typeof(Program).Assembly; // Get all custom attribute data foreach (var attribute in assembly.GetCustomAttributesData()) { // try to find a value if (!attribute.TryParse(out string value)) { value = string.Empty; } // write name and value if (!string.IsNullOrWhiteSpace(value)) { logger.LogInformation($"{attribute.AttributeType.Name} - {value}"); } } var whoIAm = new ElectorInfo() { ApplicationName = "Demo_RedisElector_Singleton", LastCallUtc = DateTime.UtcNow, UniqueInstanceId = Guid.NewGuid().ToString() }; logger.LogInformation("I Am: {0}", whoIAm.ToString()); var redisConfig = GetConfig("p-redis", fallbackFilename); var prov = new RedisElectorProvider(redisConfig); prov.SetExpirationMilliseconds(RedisElectorProvider.Recommended_ExpirationMilliseconds); while (shouldRun) { if (prov.AmIPrimary(whoIAm)) { if (dice.Next(1, 100) > 70) { int waiter = RedisElectorProvider.Recommended_ExpirationMilliseconds * 2; logger.LogWarning("{0} for {1} ms, Primary Faulting", whoIAm.UniqueInstanceId, waiter); prov.ForceElection(whoIAm.ApplicationName); Thread.Sleep(waiter); } else { // Fake: Unit of Work int waiter = dice.Next(RedisElectorProvider.Minimim_ExpirationMilliseconds, RedisElectorProvider.Recommended_ExpirationMilliseconds * 2); logger.LogInformation("{0} for {1} ms, Primary Working", whoIAm.UniqueInstanceId, waiter); Thread.Sleep(waiter); } } else { int waiter = RedisElectorProvider.Minimim_ExpirationMilliseconds; logger.LogInformation("{0} for {1} ms, Not Primary", whoIAm.UniqueInstanceId, waiter); Thread.Sleep(waiter); } } Environment.ExitCode = exitCode; return(exitCode); }