mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Coop: split lock checks (per-minute) from resolution (daily)
Locks were gated behind the same once-per-day 08:00 UTC tick as floor resolution. A run created after morningHour would wait until next day's tick to be eligible — meaning actual lock latency could be 24-48h, not the 24h advertised. Worse, a run created late on Day N missed the Day N+1 tick (too early) AND the Day N+2 tick happens 48h after creation. Fix: lock checks fire on every ticker minute (cheap timestamp scan over typically 0-5 open runs). Resolution stays daily, gated by JobCompleted. Real symptom that prompted this: Run #1 created 17:17 UTC, locked never fired because the morning tick at 08:00 UTC the next day saw the run as not-yet-eligible (only 15h elapsed), then marked the daily job complete before the actual 24h elapsed at 17:17 UTC. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,20 +14,24 @@ import (
|
|||||||
"maunium.net/go/mautrix/id"
|
"maunium.net/go/mautrix/id"
|
||||||
)
|
)
|
||||||
|
|
||||||
// coopTicker fires once per UTC day to:
|
// coopTicker has two cadences:
|
||||||
// 1. Lock open invites whose 24h window has elapsed.
|
|
||||||
// 2. For each active run, resolve the day's floor and advance/complete.
|
|
||||||
//
|
//
|
||||||
// Reuses the daily_prefetch job-completion guard so a bot restart on the same
|
// 1. Lock checks fire every minute. They're cheap (one timestamp comparison
|
||||||
// UTC day does not double-process.
|
// per open run) and a 24h invite window is poorly served by a 24h tick —
|
||||||
|
// a run started after 08:00 UTC would otherwise wait 30-48h to lock.
|
||||||
|
// 2. Floor resolution fires once per UTC day at morningHour, gated by the
|
||||||
|
// daily_prefetch JobCompleted guard. Resolution is the heavy step that
|
||||||
|
// advances days, distributes rewards, and posts to the room.
|
||||||
func (p *AdventurePlugin) coopTicker() {
|
func (p *AdventurePlugin) coopTicker() {
|
||||||
ticker := time.NewTicker(1 * time.Minute)
|
ticker := time.NewTicker(1 * time.Minute)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
|
// Locks: every minute.
|
||||||
|
p.coopProcessLocks()
|
||||||
|
|
||||||
|
// Resolutions: once per day at morningHour:00 UTC.
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
// Run at the same minute as the morning DM (08:00 UTC) — same cadence as
|
|
||||||
// the rest of the adventure system.
|
|
||||||
if now.Hour() != p.morningHour || now.Minute() != 0 {
|
if now.Hour() != p.morningHour || now.Minute() != 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -36,8 +40,7 @@ func (p *AdventurePlugin) coopTicker() {
|
|||||||
if db.JobCompleted(jobName, dateKey) {
|
if db.JobCompleted(jobName, dateKey) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
slog.Info("coop: daily tick")
|
slog.Info("coop: daily tick — resolving active runs")
|
||||||
p.coopProcessLocks()
|
|
||||||
p.coopProcessActiveRuns()
|
p.coopProcessActiveRuns()
|
||||||
db.MarkJobCompleted(jobName, dateKey)
|
db.MarkJobCompleted(jobName, dateKey)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user