From b31813c210deea6fa19ba94c96a55296a3b0ec40 Mon Sep 17 00:00:00 2001 From: Noikoio Date: Mon, 9 Dec 2019 19:43:43 -0800 Subject: [PATCH] Change frequency of automatic birthday role checks Changed up how the background services behave. Removed tick count, greatly increased the interval, and added a manual call to update individual guilds as their information changes. Further changes to this may be made in the near future, going as far as to possibly remvoe this structure altogether. --- BirthdayBot/BackgroundServiceRunner.vb | 11 +++--- .../BackgroundServices/BackgroundService.vb | 2 +- .../BackgroundServices/BirthdayRoleUpdate.vb | 39 ++++++++++--------- .../BackgroundServices/GuildStatistics.vb | 5 +-- BirthdayBot/BackgroundServices/Heartbeat.vb | 13 +++---- BirthdayBot/BirthdayBot.vb | 4 ++ BirthdayBot/BirthdayBot.vbproj | 2 +- 7 files changed, 38 insertions(+), 38 deletions(-) diff --git a/BirthdayBot/BackgroundServiceRunner.vb b/BirthdayBot/BackgroundServiceRunner.vb index f132c07..42240ae 100644 --- a/BirthdayBot/BackgroundServiceRunner.vb +++ b/BirthdayBot/BackgroundServiceRunner.vb @@ -4,24 +4,24 @@ ''' Handles the execution of periodic background tasks. ''' Class BackgroundServiceRunner - Const Interval = 45 ' Tick interval in seconds. Adjust as needed. + Const Interval = 8 * 60 ' Tick interval in seconds. Adjust as needed. Private ReadOnly Property Workers As List(Of BackgroundService) Private ReadOnly Property WorkerCancel As New CancellationTokenSource + Friend ReadOnly Property BirthdayUpdater As BirthdayRoleUpdate Private _workerTask As Task - Private _tickCount As Integer Sub New(instance As BirthdayBot) + BirthdayUpdater = New BirthdayRoleUpdate(instance) Workers = New List(Of BackgroundService) From { {New GuildStatistics(instance)}, {New Heartbeat(instance)}, - {New BirthdayRoleUpdate(instance)} + {BirthdayUpdater} } End Sub Public Sub Start() - _tickCount = 0 _workerTask = Task.Factory.StartNew(AddressOf WorkerLoop, WorkerCancel.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default) End Sub @@ -43,7 +43,7 @@ Class BackgroundServiceRunner ' Execute background tasks. Dim tasks As New List(Of Task) For Each service In Workers - tasks.Add(service.OnTick(_tickCount)) + tasks.Add(service.OnTick()) Next Await Task.WhenAll(tasks) Catch ex As TaskCanceledException @@ -52,7 +52,6 @@ Class BackgroundServiceRunner Log("Background task", "Unhandled exception in background task thread:") Log("Background task", ex.ToString()) End Try - _tickCount += 1 End While End Function End Class diff --git a/BirthdayBot/BackgroundServices/BackgroundService.vb b/BirthdayBot/BackgroundServices/BackgroundService.vb index 86ab79f..9c44048 100644 --- a/BirthdayBot/BackgroundServices/BackgroundService.vb +++ b/BirthdayBot/BackgroundServices/BackgroundService.vb @@ -13,5 +13,5 @@ MustInherit Class BackgroundService Program.Log(Me.GetType().Name, message) End Sub - MustOverride Function OnTick(tick As Integer) As Task + MustOverride Function OnTick() As Task End Class diff --git a/BirthdayBot/BackgroundServices/BirthdayRoleUpdate.vb b/BirthdayBot/BackgroundServices/BirthdayRoleUpdate.vb index 0d0acc1..8d718c4 100644 --- a/BirthdayBot/BackgroundServices/BirthdayRoleUpdate.vb +++ b/BirthdayBot/BackgroundServices/BirthdayRoleUpdate.vb @@ -4,22 +4,20 @@ Imports Discord.WebSocket Imports NodaTime ''' -''' Periodically scans all known guilds and adjusts birthday role membership as necessary. -''' Also handles birthday announcements. +''' Core automatic functionality of the bot. Manages role memberships based on birthday information, +''' and optionally sends the announcement message to appropriate guilds. ''' Class BirthdayRoleUpdate Inherits BackgroundService - Private ReadOnly Property Clock As IClock Public Sub New(instance As BirthdayBot) MyBase.New(instance) - Clock = SystemClock.Instance ' can be replaced with FakeClock during testing End Sub ''' - ''' Initial processing: Sets up a task per guild and waits on all. + ''' Does processing on all available guilds at once. ''' - Public Overrides Async Function OnTick(tick As Integer) As Task + Public Overrides Async Function OnTick() As Task Dim tasks As New List(Of Task(Of Integer)) For Each guild In BotInstance.DiscordClient.Guilds Dim t = ProcessGuildAsync(guild) @@ -38,19 +36,24 @@ Class BirthdayRoleUpdate Next End Try - ' Usage report: Show how many announcements were done - Dim announces = 0 - Dim guilds = 0 - For Each task In tasks - If task.Result > 0 Then - announces += task.Result - guilds += 1 - End If - Next - If announces > 0 Then Log($"Announcing {announces} birthday(s) in {guilds} guild(s).") + ' TODO metrics for role sets, unsets, announcements - and how to do that for singles too? End Function - Async Function ProcessGuildAsync(guild As SocketGuild) As Task(Of Integer) + ''' + ''' Does role and announcement processing for a single specified guild. + ''' + Public Async Function SingleUpdateFor(guild As SocketGuild) As Task + Try + Await ProcessGuildAsync(guild) + Catch ex As Exception + Log("Encountered an error during guild processing:") + Log(ex.ToString()) + End Try + + ' TODO metrics for role sets, unsets, announcements - and I mentioned this above too + End Function + + Private Async Function ProcessGuildAsync(guild As SocketGuild) As Task(Of Integer) ' Gather required information Dim tz As String Dim users As IEnumerable(Of GuildUserSettings) @@ -156,7 +159,7 @@ Class BirthdayRoleUpdate Dim targetMonth = item.BirthMonth Dim targetDay = item.BirthDay - Dim checkNow = Clock.GetCurrentInstant().InZone(tz) + Dim checkNow = SystemClock.Instance.GetCurrentInstant().InZone(tz) ' Special case: If birthday is February 29 and it's not a leap year, recognize it on March 1st If targetMonth = 2 And targetDay = 29 And Not Date.IsLeapYear(checkNow.Year) Then targetMonth = 3 diff --git a/BirthdayBot/BackgroundServices/GuildStatistics.vb b/BirthdayBot/BackgroundServices/GuildStatistics.vb index 82233b8..6679176 100644 --- a/BirthdayBot/BackgroundServices/GuildStatistics.vb +++ b/BirthdayBot/BackgroundServices/GuildStatistics.vb @@ -10,10 +10,7 @@ Class GuildStatistics DBotsToken = instance.Config.DBotsToken End Sub - Public Overrides Async Function OnTick(tick As Integer) As Task - ' Activate roughly every 2 hours (interval: 45) - If tick Mod 160 <> 2 Then Return - + Public Overrides Async Function OnTick() As Task Dim count = BotInstance.DiscordClient.Guilds.Count Log($"Currently in {count} guild(s).") diff --git a/BirthdayBot/BackgroundServices/Heartbeat.vb b/BirthdayBot/BackgroundServices/Heartbeat.vb index 15eba4b..db06770 100644 --- a/BirthdayBot/BackgroundServices/Heartbeat.vb +++ b/BirthdayBot/BackgroundServices/Heartbeat.vb @@ -1,5 +1,5 @@ ''' -''' Basic heartbeat function - indicates that the background task is still functioning. +''' Basic heartbeat function - hints that the background task is still alive. ''' Class Heartbeat Inherits BackgroundService @@ -8,19 +8,16 @@ Class Heartbeat MyBase.New(instance) End Sub - Public Overrides Function OnTick(tick As Integer) As Task - ' Print a message roughly every 15 minutes (assuming 45s per tick). - If tick Mod 20 = 0 Then - Dim uptime = DateTimeOffset.UtcNow - Program.BotStartTime - Log($"Tick {tick:00000} - Bot uptime: {BotUptime()}") - End If + Public Overrides Function OnTick() As Task + Dim uptime = DateTimeOffset.UtcNow - Program.BotStartTime + Log($"Bot uptime: {BotUptime()}") ' Disconnection warn For Each shard In BotInstance.DiscordClient.Shards If shard.ConnectionState = Discord.ConnectionState.Disconnected Then Log($"Shard {shard.ShardId} is disconnected! Restart the app if this persists.") ' The library alone cannot be restarted as it is in an unknown state. It was not designed to be restarted. - ' This is the part where we'd signal something to restart us if we were fancy. + ' TODO This is the part where we'd signal something to restart us if we were fancy. End If Next diff --git a/BirthdayBot/BirthdayBot.vb b/BirthdayBot/BirthdayBot.vb index 5d9f7ed..330ce79 100644 --- a/BirthdayBot/BirthdayBot.vb +++ b/BirthdayBot/BirthdayBot.vb @@ -118,6 +118,7 @@ Class BirthdayBot End If End If + ' Execute the command Try Log("Command", $"{channel.Guild.Name}/{author.Username}#{author.Discriminator}: {msg.Content}") Await command(csplit, channel, author) @@ -130,6 +131,9 @@ Class BirthdayBot ' Fail silently. End Try End Try + + ' Immediately check for role updates in the invoking guild + Await _worker.BirthdayUpdater.SingleUpdateFor(channel.Guild) End If End If End Function diff --git a/BirthdayBot/BirthdayBot.vbproj b/BirthdayBot/BirthdayBot.vbproj index 410e126..93b9408 100644 --- a/BirthdayBot/BirthdayBot.vbproj +++ b/BirthdayBot/BirthdayBot.vbproj @@ -4,7 +4,7 @@ Exe BirthdayBot netcoreapp2.0 - 1.3.3 + 1.3.4 Noi Discord bot for birthday reminders.