refactor: Improve weather art generation process
- Add formatted_current_time method to City model. - Modify BatchGenerateWeatherArtsWorker to check local time. - Update Sidekiq scheduler to run every hour. This commit improves the weather art generation by considering local time for image generation and increasing the frequency of batch processing for testing purposes. The new method provides formatted time information for each city. This change ensures that images are generated during daylight hours.
This commit is contained in:
parent
df074a81a8
commit
936db76437
@ -109,7 +109,7 @@ class City < ApplicationRecord
|
||||
|
||||
# 定义 latest_weather_art 关联
|
||||
has_one :latest_weather_art, -> { order(weather_date: :desc) },
|
||||
class_name: 'WeatherArt'
|
||||
class_name: "WeatherArt"
|
||||
|
||||
# 包含最新天气艺术的 scope
|
||||
scope :with_latest_weather_art, -> {
|
||||
@ -124,14 +124,14 @@ class City < ApplicationRecord
|
||||
# 按最新天气更新时间排序
|
||||
scope :order_by_latest_weather, -> {
|
||||
joins(:weather_arts)
|
||||
.group('cities.id')
|
||||
.order('MAX(weather_arts.weather_date) DESC')
|
||||
.group("cities.id")
|
||||
.order("MAX(weather_arts.weather_date) DESC")
|
||||
}
|
||||
|
||||
# 获取最近24小时内更新过天气的城市
|
||||
scope :recently_updated, -> {
|
||||
joins(:weather_arts)
|
||||
.where('weather_arts.weather_date > ?', 24.hours.ago)
|
||||
.where("weather_arts.weather_date > ?", 24.hours.ago)
|
||||
.distinct
|
||||
}
|
||||
|
||||
@ -213,5 +213,36 @@ class City < ApplicationRecord
|
||||
self.id)
|
||||
.count
|
||||
end
|
||||
end
|
||||
|
||||
def formatted_current_time(type = :date, use_local_timezone = true)
|
||||
# 获取时区
|
||||
timezone_info = self.country&.timezones.present? ?
|
||||
eval(self.country.timezones).first :
|
||||
{ "zoneName" => "UTC", "gmtOffsetName" => "UTC+00:00" }
|
||||
|
||||
# 设置时区对象
|
||||
time_zone = ActiveSupport::TimeZone[timezone_info["zoneName"]] ||
|
||||
ActiveSupport::TimeZone["UTC"]
|
||||
time = Time.current
|
||||
|
||||
case type
|
||||
when :date
|
||||
# 格式化日期
|
||||
time.strftime("%B %d, %Y")
|
||||
when :time
|
||||
use_local_timezone ?
|
||||
"#{time.in_time_zone(time_zone).strftime('%H:%M')} #{timezone_info['gmtOffsetName']}" :
|
||||
"#{time.utc.strftime('%H:%M')} UTC"
|
||||
when :all
|
||||
# 返回日期 + 时间 + UTC 信息
|
||||
date = time.strftime("%B %d, %Y")
|
||||
time = use_local_timezone ?
|
||||
updated_at.in_time_zone(time_zone).strftime("%H:%M") + " #{timezone_info['gmtOffsetName']}" :
|
||||
updated_at.utc.strftime("%H:%M") + " UTC"
|
||||
"#{date} #{time}"
|
||||
else
|
||||
"Unknown #{type}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -2,8 +2,8 @@ class BatchGenerateWeatherArtsWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
GENERATION_INTERVAL = 36.hours
|
||||
MAX_DURATION = 50.minutes
|
||||
SLEEP_DURATION = 120.seconds
|
||||
MAX_DURATION = 5.minutes
|
||||
SLEEP_DURATION = 10.seconds
|
||||
DAILY_GENERATION_LIMIT = 50 # 每日生成图片上限
|
||||
|
||||
def perform(*args)
|
||||
@ -11,10 +11,26 @@ class BatchGenerateWeatherArtsWorker
|
||||
remaining_slots = calculate_remaining_slots
|
||||
return if remaining_slots <= 0
|
||||
|
||||
# 获取符合条件的城市并处理
|
||||
cities_to_process = select_cities(remaining_slots)&.shuffle
|
||||
print_cities_list(cities_to_process, start_time)
|
||||
process_cities(cities_to_process, start_time)
|
||||
|
||||
skipped_cities = []
|
||||
processed_cities = []
|
||||
|
||||
cities_to_process.each do |city|
|
||||
if within_sunrise_time?(city)
|
||||
Rails.logger.info "Generating weather art for #{city.name}"
|
||||
GenerateWeatherArtWorker.perform_async(city.id)
|
||||
processed_cities << city.name
|
||||
else
|
||||
Rails.logger.info "Skipping #{city.name} due to local time not being within sunrise hours."
|
||||
skipped_cities << city.name
|
||||
end
|
||||
sleep SLEEP_DURATION
|
||||
break if Time.current - start_time > MAX_DURATION
|
||||
end
|
||||
|
||||
print_summary(processed_cities, skipped_cities)
|
||||
end
|
||||
|
||||
private
|
||||
@ -25,23 +41,42 @@ class BatchGenerateWeatherArtsWorker
|
||||
.where.not(image_attachment: nil)
|
||||
.count
|
||||
|
||||
[ DAILY_GENERATION_LIMIT - today_generations, 0 ].max
|
||||
[DAILY_GENERATION_LIMIT - today_generations, 0].max
|
||||
end
|
||||
|
||||
def print_cities_list(cities, start_time)
|
||||
Rails.logger.info "Generate city task start at: #{start_time}"
|
||||
Rails.logger.info "Generate city list: "
|
||||
Rails.logger.info "======================================"
|
||||
Rails.logger.info "ID\tRegion\tCountry\tState\tName"
|
||||
Rails.logger.info "ID\tRegion\tCountry\tState\tName\tLocalTime"
|
||||
cities.each do |city|
|
||||
Rails.logger.info "#{city.id}\t#{city&.country&.region&.name}\t#{city&.country&.name}\t#{city&.state&.name}\t#{city&.name}"
|
||||
Rails.logger.info "#{city.id}\t#{city.country&.region&.name}\t#{city.country&.name}\t#{city.state&.name}\t#{city.name}\t#{city.formatted_current_time(:all)}"
|
||||
end
|
||||
end
|
||||
|
||||
def within_sunrise_time?(city)
|
||||
local_time = get_local_time(city)
|
||||
local_time.hour >= 8 && local_time.hour <= 18
|
||||
end
|
||||
|
||||
def get_local_time(city)
|
||||
return Time.current unless city
|
||||
timezone_info = city.country&.timezones&.first
|
||||
return Time.current unless timezone_info
|
||||
|
||||
timezone = ActiveSupport::TimeZone["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
|
||||
@ -50,7 +85,6 @@ class BatchGenerateWeatherArtsWorker
|
||||
) 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)
|
||||
@ -60,7 +94,6 @@ class BatchGenerateWeatherArtsWorker
|
||||
remaining_slots = limit - active_cities.size
|
||||
|
||||
if remaining_slots > 0
|
||||
# 如果还有剩余名额,从其他城市中随机选择
|
||||
other_cities = base_query
|
||||
.where.not(id: active_cities.map(&:id))
|
||||
.order("RANDOM()")
|
||||
@ -72,14 +105,4 @@ class BatchGenerateWeatherArtsWorker
|
||||
active_cities
|
||||
end
|
||||
end
|
||||
|
||||
def process_cities(cities, start_time)
|
||||
cities.each do |city|
|
||||
break if Time.current - start_time > MAX_DURATION
|
||||
|
||||
Rails.logger.info "Generating weather art for #{city.name}"
|
||||
GenerateWeatherArtWorker.perform_async(city.id)
|
||||
sleep SLEEP_DURATION
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,5 +1,5 @@
|
||||
batch_generate_weather:
|
||||
cron: '0 8,18 * * *'
|
||||
cron: '0 */1 * * *'
|
||||
class: BatchGenerateWeatherArtsWorker
|
||||
description: "Batch Generate weather arts"
|
||||
enabled: true
|
||||
|
Loading…
Reference in New Issue
Block a user