I'm upgrading my open-source Ruby on Rails app from Rails 6.0.x to Rails 6.1.x
The upgrade went fine, except now I get an error from an async ActiveJob that fetches RSS feeds. When my app is deployed locally in development, I get one error:
[ActiveJob] [UpdateFeedJob] [80202040-f40d-46ae-8841-94cf03afbd6c] Error performing UpdateFeedJob (Job ID: 80202040-f40d-46ae-8841-94cf03afbd6c) from Async(default) in 366.36ms: ArgumentError (wrong number of arguments (given 1, expected 0)):
/Users/matt/.rbenv/versions/2.7.6/lib/ruby/2.7.0/rss/rss.rb:53:in `w3cdtf'
/Users/matt/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activesupport-6.1.7.3/lib/active_support/time_with_zone.rb:208:in `to_s'
...
/Users/matt/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activerecord-6.1.7.3/lib/active_record/associations/collection_proxy.rb:348:in `create'
/Users/matt/git/haven/haven/app/jobs/update_feed_job.rb:104:in `block (2 levels) in update_feed'
/Users/matt/git/haven/haven/app/jobs/update_feed_job.rb:79:in `each'
/Users/matt/git/haven/haven/app/jobs/update_feed_job.rb:79:in `block in update_feed'
/Users/matt/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activerecord-6.1.7.3/lib/active_record/locking/pessimistic.rb:88:in `block in with_lock'
...
/Users/matt/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activerecord-6.1.7.3/lib/active_record/locking/pessimistic.rb:86:in `with_lock'
/Users/matt/git/haven/haven/app/jobs/update_feed_job.rb:69:in `update_feed'
/Users/matt/git/haven/haven/app/jobs/update_feed_job.rb:29:in `block in perform'
/Users/matt/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activerecord-6.1.7.3/lib/active_record/relation/batches.rb:71:in `block (2 levels) in find_each'
...
When deployed remotely in production on AWS I get a slightly different error:
E, [2023-04-25T06:46:06.355616 #30503] ERROR -- : [ActiveJob] [UpdateFeedJob] [2996357f-8dd2-4b97-a367-e0be19fb5a16] Error performing UpdateFeedJob (Job ID: 2996357f-8dd2-4b97-a367-e0be19fb5a16) from Async(default) in 1526.52ms: ArgumentError (wrong number of arguments (given 1, expected 0)):
/home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/2.7.0/time.rb:661:in `rfc2822'
/var/www/haven/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.7.3/lib/active_support/time_with_zone.rb:208:in `to_s'
...
/var/www/haven/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.7.3/lib/active_record/associations/collection_proxy.rb:348:in `create'
/var/www/haven/app/jobs/update_feed_job.rb:104:in `block (2 levels) in update_feed'
/var/www/haven/app/jobs/update_feed_job.rb:79:in `each'
/var/www/haven/app/jobs/update_feed_job.rb:79:in `block in update_feed'
/var/www/haven/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.7.3/lib/active_record/locking/pessimistic.rb:88:in `block in with_lock'
...
/var/www/haven/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.7.3/lib/active_record/locking/pessimistic.rb:86:in `with_lock'
/var/www/haven/app/jobs/update_feed_job.rb:69:in `update_feed'
/var/www/haven/app/jobs/update_feed_job.rb:29:in `block in perform'
/var/www/haven/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.7.3/lib/active_record/relation/batches.rb:71:in `block (2 levels) in find_each'
...
On Rails 6.1, the active_support/time_with_zone.rb
code calls:
utc.to_s(format)
Where on Rails 6.0 it calls the same thing.
Maybe the underlying utc
object's type changed between Rails 6.0 and 6.1? I'm trying to wrap my head around how to start debugging this. It seems like a bug in Rails 6.1, but it could also be a bug I was relying on that got fixed in 6.1. I tried upgrading from Ruby 2.7 to Ruby 3.0 and the issue persisted.
Any pointers on where to look next would be much appreciated.
It looks like something to do with supported date formats. I've got a resolution, but not a full understanding of what's going on.
The job is fetching RSS and Atom feeds using Ruby's built-in rss
library which will generate a Time
object from the feed xml (for feed entry publish time). Depending on the feed or the format of the feed, it breaks--specifically xkcd.com's atom feed started breaking.
Saving a record with a datetime
db type works fine if it is formatted as Mon, 30 May 2022 00:00:00 +0000
, but breaks for something formatted as 2023-04-21T00:00:00Z
. So I re-parse the time value: time = Time.parse(time.httpdate)
.
I presume this is an interaction between what the rss library does with dates and what rails/activesupport does with dates. Both rss-parsed strings self-report a type of Time
but show original formats under to_s
. Activesupport also does some screwy things that made further debugging more challenging, eg:
class TimeWithZone
# Report class name as 'Time' to thwart type checking.
def self.name
"Time"
end