From 4131d2f22c16d9abd1071ff8a7c0675e7db94a5a Mon Sep 17 00:00:00 2001 From: jetsparrow Date: Thu, 22 Apr 2021 17:41:35 +0300 Subject: [PATCH] Redo heartbeats to save heart attack events --- JetHerald/Controllers/HeartbeatController.cs | 16 +++++-- JetHerald/Db.cs | 48 ++++++++++---------- JetHerald/JetHeraldBot.cs | 15 ++++-- 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/JetHerald/Controllers/HeartbeatController.cs b/JetHerald/Controllers/HeartbeatController.cs index a63a490..40aa556 100644 --- a/JetHerald/Controllers/HeartbeatController.cs +++ b/JetHerald/Controllers/HeartbeatController.cs @@ -56,18 +56,25 @@ namespace JetHerald.Controllers } } + [Route("api/heartbeat")] + [HttpGet] + public Task HeartbeatGet(HeartbeatArgs args) => DoHeartbeat(args); + private async Task DoHeartbeat(HeartbeatArgs args) { + var heart = args.Heart ?? "General"; + var t = await Db.GetTopic(args.Topic); if (t == null) return new NotFoundResult(); - else if (!t.WriteToken.Equals(args.WriteToken, StringComparison.OrdinalIgnoreCase)) + else if (!t.WriteToken.Equals(args.WriteToken, StringComparison.Ordinal)) return StatusCode(403); - if (t.ExpiryMessageSent) - await Herald.HeartbeatSent(t); + + var affected = await Db.ReportHeartbeat(t.TopicId, heart, args.ExpiryTimeout); - await Db.AddExpiry(t.Name, args.ExpiryTimeout); + if (affected == 1) + await Herald.HeartbeatSent(t); return new OkResult(); } @@ -75,6 +82,7 @@ namespace JetHerald.Controllers public class HeartbeatArgs { [JsonPropertyName("Topic")] public string Topic; + [JsonPropertyName("Heart")] public string Heart; [JsonPropertyName("ExpiryTimeout")] public int ExpiryTimeout; [JsonPropertyName("WriteToken")] public string WriteToken; } diff --git a/JetHerald/Db.cs b/JetHerald/Db.cs index 7cf4960..8a31d49 100644 --- a/JetHerald/Db.cs +++ b/JetHerald/Db.cs @@ -28,11 +28,14 @@ namespace JetHerald => Name == Description ? Name : $"{Name}: {Description}"; } - public class ExpiredTopicChat + public class HeartAttack { - public NamespacedId Chat; - public string Description; + public ulong HeartattackId { get; set; } + public uint TopicId { get; set; } + public string Heart { get; set; } public DateTime ExpiryTime { get; set; } + + public string Description { get; set; } } public async Task DeleteTopic(string name, string adminToken) @@ -131,38 +134,37 @@ namespace JetHerald new { topicName, chat }); } - public Task AddExpiry(string topicName, int addedTime) + + public async Task ReportHeartbeat(uint topicId, string heart, int timeoutSeconds) { using var c = GetConnection(); - return c.ExecuteAsync( - " UPDATE topic" + - " SET ExpiryTime = CURRENT_TIMESTAMP() + INTERVAL @addedTime SECOND," + - " ExpiryMessageSent = 0" + - " WHERE Name = @topicName", - new { topicName, addedTime }); + return await c.ExecuteAsync( + @" + INSERT INTO heartbeat + (TopicId, Heart, ExpiryTime) + VALUES + (@topicId, @heart, @expiry) + ON DUPLICATE KEY UPDATE + ExpiryTime = @expiry; + ", + new { topicId, heart, expiry = DateTime.UtcNow.AddSeconds(timeoutSeconds)}); } - public Task> GetExpiredTopics(CancellationToken token = default) + public async Task> ProcessHeartAttacks() { using var c = GetConnection(); - return c.QueryAsync( - " SELECT tc.Chat, t.Description, t.ExpiryTime" + - " FROM topic_chat tc" + - " INNER JOIN topic t ON t.TopicId = tc.TopicId" + - " WHERE t.ExpiryTime < CURRENT_TIMESTAMP() AND NOT t.ExpiryMessageSent", - token); + return await c.QueryAsync("CALL process_heartattacks();"); } - public Task MarkExpiredTopics(CancellationToken token = default) + public async Task MarkHeartAttackReported(ulong id) { using var c = GetConnection(); - return c.ExecuteAsync( - " UPDATE topic t" + - " SET t.ExpiryMessageSent = 1" + - " WHERE t.ExpiryTime < CURRENT_TIMESTAMP()", - token); + await c.ExecuteAsync("UPDATE heartattack SET Reported = 1 WHERE HeartattackId = @id", new {id}); } + + + public Db(IOptions cfg) { Config = cfg.Value; diff --git a/JetHerald/JetHeraldBot.cs b/JetHerald/JetHeraldBot.cs index 914e17d..3c86e60 100644 --- a/JetHerald/JetHeraldBot.cs +++ b/JetHerald/JetHeraldBot.cs @@ -88,13 +88,18 @@ namespace JetHerald while (!token.IsCancellationRequested) { await Task.Delay(1000 * 10, token); - try { - foreach (var chatSent in await Db.GetExpiredTopics(token)) - await SendMessageImpl(chatSent.Chat, $"!{chatSent.Description}!:\nTimeout expired at {chatSent.ExpiryTime}"); - - await Db.MarkExpiredTopics(token); + var attacks = await Db.ProcessHeartAttacks(); + foreach (var attack in attacks) + { + var chats = await Db.GetChatsForTopic(attack.TopicId); + foreach (var chat in chats) + await SendMessageImpl(chat, $"!{attack.Description}!:\nTimeout expired at {attack.ExpiryTime}"); + await Db.MarkHeartAttackReported(attack.HeartattackId); + if (token.IsCancellationRequested) + return; + } } catch (Exception e) {