diff --git a/db/migrations/11_event_levels.sql b/db/migrations/11_event_levels.sql index ef76631..49fbe60 100644 --- a/db/migrations/11_event_levels.sql +++ b/db/migrations/11_event_levels.sql @@ -7,7 +7,8 @@ CREATE TABLE daily_queue ( CREATE TABLE daily_levels ( level_id INTEGER NOT NULL references levels(id), idx SERIAL NOT NULL PRIMARY KEY, - expires_at TEXT NOT NULL + expires_at TEXT NOT NULL, + queue_idx INTEGER NOT NULL references daily_queue(idx) ); CREATE TABLE weekly_queue ( @@ -18,7 +19,8 @@ CREATE TABLE weekly_queue ( CREATE TABLE weekly_levels ( level_id INTEGER NOT NULL references levels(id), idx SERIAL NOT NULL PRIMARY KEY, - expires_at TEXT NOT NULL + expires_at TEXT NOT NULL, + queue_idx INTEGER NOT NULL references weekly_queue(idx) ); -- +migrate down diff --git a/src/lib/dailies.cr b/src/lib/dailies.cr index da986de..b25a08d 100644 --- a/src/lib/dailies.cr +++ b/src/lib/dailies.cr @@ -7,28 +7,35 @@ module CrystalGauntlet::Dailies WEEKLY_OFFSET = 100001 - def grab_new_level(weekly : Bool, prev = Time.utc) : {Int32 | Nil, Int32 | Nil, Int32 | Nil} - LOG.debug { "grabbing new event level, weekly: #{weekly}" } + def grab_new_level(weekly : Bool, prev = Time.utc, prev_idx = 0) : {Int32?, Int32?, Int32?} + LOG.debug { "grabbing new event level, weekly: #{weekly} (previous queue index #{prev_idx})" } + begin - level_id = DATABASE.query_one("select level_id from #{weekly ? "weekly_queue" : "daily_queue"} order by idx desc limit 1", as: {Int32}) + level_id, new_idx = DATABASE.query_one("select level_id, idx from #{weekly ? "weekly_queue" : "daily_queue"} where idx > #{prev_idx} order by idx limit 1", as: {Int32, Int32}) rescue - LOG.debug { "can't find anything in queue" } - return {nil, nil, nil} - else - next_id = IDs.get_next_id(weekly ? "weekly_levels" : "daily_levels") - # todo: configurable? - timespan = weekly ? 1.weeks : 1.days - LOG.debug { "#{level_id} for #{timespan}" } - expires_at = prev + timespan - DATABASE.exec("insert into #{weekly ? "weekly_levels" : "daily_levels"} (level_id, idx, expires_at) values (?, ?, ?)", level_id, next_id, expires_at.to_s(Format::TIME_FORMAT)) - return {level_id, timespan.total_seconds.to_i, next_id} + LOG.debug { "can't find new level in queue, attempting reuse" } + begin + level_id, new_idx = DATABASE.query_one("select level_id, idx from #{weekly ? "weekly_queue" : "daily_queue"} order by idx desc limit 1", as: {Int32, Int32}) + rescue + LOG.debug { "no levels in queue; quitting out" } + return {nil, nil, nil} + end end + + next_id = IDs.get_next_id(weekly ? "weekly_levels" : "daily_levels") + # todo: configurable? + timespan = weekly ? 1.weeks : 1.days + LOG.debug { "#{level_id} for #{timespan}" } + expires_at = prev + timespan + DATABASE.exec("insert into #{weekly ? "weekly_levels" : "daily_levels"} (level_id, idx, expires_at, queue_idx) values (?, ?, ?, ?)", level_id, next_id, expires_at.to_s(Format::TIME_FORMAT), new_idx) + + return {level_id, timespan.total_seconds.to_i, next_id} end def fetch_current_level(weekly : Bool) : {Int32 | Nil, Int32 | Nil, Int32 | Nil} LOG.debug { "getting current event level, weekly: #{weekly}" } begin - level_id, expires_at, idx = DATABASE.query_one("select level_id, expires_at, idx from #{weekly ? "weekly_levels" : "daily_levels"} order by idx desc limit 1", as: {Int32, String, Int32}) + level_id, expires_at, idx, queue_idx = DATABASE.query_one("select level_id, expires_at, idx, queue_idx from #{weekly ? "weekly_levels" : "daily_levels"} order by idx desc limit 1", as: {Int32, String, Int32, Int32}) LOG.debug { "#{level_id} (#{idx}), expiring at #{expires_at}" } rescue # make up a brand new daily; using current time because no previous ones have existed @@ -39,7 +46,7 @@ module CrystalGauntlet::Dailies expires = (Time.parse(expires_at, Format::TIME_FORMAT, Time::Location::UTC) - Time.utc).total_seconds.to_i if expires <= 0 LOG.debug { "expired!!" } - level_id, expires, idx = grab_new_level(weekly, Time.parse(expires_at, Format::TIME_FORMAT, Time::Location::UTC)) + level_id, expires, idx = grab_new_level(weekly, Time.parse(expires_at, Format::TIME_FORMAT, Time::Location::UTC), queue_idx) end end