2018-9-3 记录一次 Ruby on Rails [测试环境]和[生产环境]缓存干扰问题

应该是 memcached 造成的?

刚解决完这个问题。趁着记忆还新鲜赶紧写一下。

这篇文讲什么?

讲 Ruby on Rails 可能碰到的一个奇怪错误。
这个错误是在一台服务器上跑两个 puma,一个生产环境,一个测试环境导致的。

这篇文对谁有用?

Ruby on Rails 程序员

版本

Ruby on Rails 5.2.0

正文开始 ⬇️

具体问题描述

Ubuntu 16.04 服务器上跑了2个 Puma,
一个是 test environment,一个是 production environment。

在 test 环境里 修改某用户的用户名
比如如下示例代码,修改了用户id 1 的用户名变成 '3'

    u = User.find(1)
    u.username = '3'
    u.save

会导致生产环境里,用户 id 的用户名显示 3。

看到这里,你可能会想:
是不是 database.yml 里的测试环境 test 和生产环境 production 数据库写了同一个名字,所以变成了操作同一个数据库?

并没有。以下是我的 database.yml
重点:测试和生产环境用的不同数据库

default: &default
  adapter: postgresql
  pool: 64
  timeout: 5000
  encoding: utf-8
  port: 5432

production:
  <<: *default
  database: homeland

development:
  <<: *default
  database: homeland-dev

test:
  <<: *default
  database: homeland-test

临时解决方法

进入生产环境的 rails console。
运行:

    Rails.cache.clear

永久解决方案

修改2个文件:

  1. config/enviroments/test.rb
    config.cache_store = :memory_store, { size: 64.megabytes }

  2. config/memcached.yml
    原先只有 default 有 namespace,现在4个都加上了
    如 namespace: rb-dev

defaults: &defaults
  host: 127.0.0.1:11211
  namespace: rb-1
  compress: true

development:
  <<: *defaults
  namespace: rb-dev

test:
  <<: *defaults
  namespace: rb-test

production:
  <<: *defaults
  namespace: rb-production

重点:让两个环境下的缓存不要串了。这样测试环境下就不会影响到生产环境。

实测:在测试环境下修改 id 为 14 的用户名。生产环境下没有受到影响。

备注

我在这个问题上耗费了大概4-8个小时。不值。发这个文章出来是希望节省其他程序员的时间。

一个花时间的大块是当初出问题的时候,看数据库发现数据本身是没有问题的。只是返回的结果不对。
花了一点时间才找到 Rails.cache.clear 这个临时方法。
第二个花时间的大块是找永久解决方案的,先读一遍 Rails 本身的缓存策略
https://guides.rubyonrails.org/caching_with_rails.html
还有读十来篇网上和 Rails 缓存相关的文章。

最后猜测是 config.cache_store 的问题。
因为这个问题的本质就是缓存串了。两个环境的缓存都在一个地方,所以覆盖了。
然后再看现在的配置是什么情况。再改。

我其实没办法本地完美复现这个 test 和 production 环境下的缓存干扰问题。
我又没有那个心情和时间去纠结一定要完美复现这个问题。
所以以上的方法在我测的时候是没问题的。实际是否完美解决办法不清楚。
先观察一阵子。有情况再更新。