Memcached uses local time instead of configured time zone

Hi all, I noticed a strange behavior with Memcached store. The first time I store an model object, Memcached correctly store the timestamps, using the configured time zone (UTC for me).

When I update that object and cache it again, Memcached uses the server local time for the updated_at attribute, instead of UTC.

comment.updated_at # => "2008-08-25 10:06:09" # UTC cached_comment.updated_at # => 2008-08-25 12:06:09" # local time

I believe it's a bug, because it doesn't behaves the same with other caching systems (:file_store and :memory_store). I experienced this problem with Rails 2.1.0 and current edge.

I already opened a ticket: http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/900-memcached-uses-local-time-instead-of-configured-time-zone

Luca Guidi wrote:

Hi all, I noticed a strange behavior with Memcached store. The first time I store an model object, Memcached correctly store the timestamps, using the configured time zone (UTC for me).

When I update that object and cache it again, Memcached uses the server local time for the updated_at attribute, instead of UTC.

comment.updated_at # => "2008-08-25 10:06:09" # UTC cached_comment.updated_at # => 2008-08-25 12:06:09" # local time

I believe it's a bug, because it doesn't behaves the same with other caching systems (:file_store and :memory_store). I experienced this problem with Rails 2.1.0 and current edge.

It seems unlikely to me that the root cause of this bug is in the memcache store, but rather something not handling marshaling correctly. Are you using the rails 2.1 timezone functionality? Perhaps the timezone aware attributes?

Can you reproduce it just by writing the date / time value to memcache on its own?

It seems like Marshal can't properly (un)serialize models with @changed_attributes, maybe because timestamps inside that hash, are instances of Time instead of TimeWithZone.

http://pastie.org/259472

Michael Koziarski wrote:

It seems unlikely to me that the root cause of this bug is in the memcache store, but rather something not handling marshaling correctly. Are you using the rails 2.1 timezone functionality? Perhaps the timezone aware attributes?

Can you reproduce it just by writing the date / time value to memcache on its own?

We've been exploring this further on the Lighthouse ticket -- indeed, the problem isn't specific to memcache; it's an issue with marshaling.

The root of the problem is, Ruby's odd/broken marshaling of Time instances -- it will always return a Time.local instance, even if you give it a Time.utc instance.

When you marshal and unmarshal an ActiveRecord instance, Time.utc objects in the attributes hash will be returned as Time.local instances -- these Time.local instances are equivalent (in seconds since epoch) to the original Time.utc instances, but they have different #to_s(:db) outputs, so they'll output the wrong values to the db.

I'm not sure of the best way to fix this. One idea would be, create custom marshal behavior for AR instances that keeps track of Time.utc instances in the attributes hash, and coerces them back to #utc on unmarshaling.

I attached a patch to the Lighthouse ticket.