refactor: improve weather art generation process
- Update city selection to consider countries. - Use daytime instead of sunrise for time checks. - Add per-run generation limit This commit refactors the weather art generation process to increase the efficiency. The city selection has been updated to consider country. Daytime check has been updated to determine if the city is within the correct local time. A limit is added to restrict the number of cities processed in a single run.
This commit is contained in:
parent
afc871deb1
commit
fa1fc7c21a
@ -5,29 +5,31 @@ class BatchGenerateWeatherArtsWorker
|
||||
MAX_DURATION = 5.minutes
|
||||
SLEEP_DURATION = 10.seconds
|
||||
DAILY_GENERATION_LIMIT = 50 # 每日生成图片上限
|
||||
PER_RUN_GENERATION_LIMIT = 5 # 每次运行生成图片上限
|
||||
|
||||
def perform(*args)
|
||||
start_time = Time.current
|
||||
remaining_slots = calculate_remaining_slots
|
||||
return if remaining_slots <= 0
|
||||
|
||||
cities_to_process = select_cities(remaining_slots)&.shuffle
|
||||
countries_to_process = select_countries
|
||||
cities_to_process = select_cities(countries_to_process, remaining_slots)&.shuffle
|
||||
print_cities_list(cities_to_process, start_time)
|
||||
|
||||
skipped_cities = []
|
||||
processed_cities = []
|
||||
|
||||
cities_to_process.each do |city|
|
||||
if within_sunrise_time?(city)
|
||||
if within_daytime?(city)
|
||||
Rails.logger.info "Generating weather art for #{city.name} (time: [#{city.formatted_current_time(:all)}])"
|
||||
GenerateWeatherArtWorker.perform_async(city.id)
|
||||
processed_cities << city.name
|
||||
else
|
||||
Rails.logger.info "Skipping #{city.name} (time: [#{city.formatted_current_time(:all)}]) due to local time not being within sunrise hours."
|
||||
Rails.logger.info "Skipping #{city.name} (time: [#{city.formatted_current_time(:all)}]) due to local time not being within daytime hours."
|
||||
skipped_cities << city.name
|
||||
end
|
||||
sleep SLEEP_DURATION
|
||||
break if Time.current - start_time > MAX_DURATION
|
||||
break if Time.current - start_time > MAX_DURATION || processed_cities.size >= PER_RUN_GENERATION_LIMIT
|
||||
end
|
||||
|
||||
print_summary(processed_cities, skipped_cities)
|
||||
@ -45,6 +47,45 @@ class BatchGenerateWeatherArtsWorker
|
||||
[ DAILY_GENERATION_LIMIT - today_generations, 0 ].max
|
||||
end
|
||||
|
||||
def select_countries
|
||||
cutoff_time = Time.current - GENERATION_INTERVAL
|
||||
|
||||
|
||||
Country.all.select do |country|
|
||||
timezone_info = country.timezones.present? ? JSON.parse(country.timezones).first : { "zoneName" => "UTC" }
|
||||
local_time = Time.current.in_time_zone(ActiveSupport::TimeZone[timezone_info["zoneName"]])
|
||||
local_time.hour >= 6 && local_time.hour <= 18
|
||||
end
|
||||
end
|
||||
|
||||
def select_cities(countries, limit)
|
||||
active_cities = City.where(active: true, country_id: countries.map(&:id)).to_a
|
||||
remaining_slots = limit - active_cities.size
|
||||
|
||||
if remaining_slots > 0
|
||||
other_cities = City
|
||||
.where.not(id: active_cities.map(&:id))
|
||||
.where(country_id: countries.map(&:id))
|
||||
.order("RANDOM()").limit(remaining_slots).to_a
|
||||
active_cities + other_cities
|
||||
else
|
||||
active_cities
|
||||
end
|
||||
end
|
||||
|
||||
def within_daytime?(city)
|
||||
local_time = get_local_time(city)
|
||||
local_time.hour >= 6 && local_time.hour <= 18
|
||||
end
|
||||
|
||||
def get_local_time(city)
|
||||
return Time.current unless city
|
||||
timezone_info = city.country&.timezones.present? ? JSON.parse(city.country.timezones).first : { "zoneName" => "UTC" }
|
||||
|
||||
timezone = ActiveSupport::TimeZone[timezone_info["zoneName"]] || ActiveSupport::TimeZone["UTC"]
|
||||
Time.current.in_time_zone(timezone)
|
||||
end
|
||||
|
||||
def print_cities_list(cities, start_time)
|
||||
Rails.logger.info "Generate city task start at: #{start_time}"
|
||||
Rails.logger.info "Generate city list: "
|
||||
@ -55,60 +96,8 @@ class BatchGenerateWeatherArtsWorker
|
||||
end
|
||||
end
|
||||
|
||||
def within_sunrise_time?(city)
|
||||
local_time = get_local_time(city)
|
||||
Rails.logger.debug "#{city.name} now hour: #{local_time.hour}"
|
||||
local_time.hour >= 8 && local_time.hour <= 18
|
||||
end
|
||||
|
||||
def get_local_time(city)
|
||||
return Time.current unless city
|
||||
timezone_info =
|
||||
city.country&.timezones.present? ?
|
||||
JSON.parse(city.country.timezones)&.first :
|
||||
{ "zoneName": "UTC" }
|
||||
|
||||
return Time.current unless timezone_info
|
||||
|
||||
timezone = ActiveSupport::TimeZone[timezone_info["zoneName"]] ||
|
||||
ActiveSupport::TimeZone["UTC"]
|
||||
Time.current.in_time_zone(timezone)
|
||||
end
|
||||
|
||||
def print_summary(processed_cities, skipped_cities)
|
||||
Rails.logger.info "Processed cities: #{processed_cities.join(', ')}"
|
||||
Rails.logger.info "Skipped cities: #{skipped_cities.join(', ')}"
|
||||
end
|
||||
|
||||
def select_cities(limit)
|
||||
cutoff_time = Time.current - GENERATION_INTERVAL
|
||||
|
||||
base_query = City
|
||||
.joins("LEFT JOIN (
|
||||
SELECT city_id, MAX(created_at) as last_generation_time
|
||||
FROM weather_arts
|
||||
GROUP BY city_id
|
||||
) latest_arts ON cities.id = latest_arts.city_id")
|
||||
.where("latest_arts.last_generation_time IS NULL OR latest_arts.last_generation_time < ?", cutoff_time)
|
||||
|
||||
active_cities = base_query
|
||||
.where(active: true)
|
||||
.order(:priority)
|
||||
.limit(limit)
|
||||
.to_a
|
||||
|
||||
remaining_slots = limit - active_cities.size
|
||||
|
||||
if remaining_slots > 0
|
||||
other_cities = base_query
|
||||
.where.not(id: active_cities.map(&:id))
|
||||
.order("RANDOM()")
|
||||
.limit(remaining_slots)
|
||||
.to_a
|
||||
|
||||
active_cities + other_cities
|
||||
else
|
||||
active_cities
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user