在使用人和浏览器的正常测试中,一切都按预期工作。但是,当我使用 rspec 时,我可以看到我有:
D, [2014-08-16T13:48:09.510013 #19418] DEBUG -- : SQL (0.6ms) UPDATE "system_flights_cacheds" SET "client_stuff" = '{"captcha":"656556"}' WHERE "system_flights_cacheds"."guid" = '5647046e-4194-498e-a0d7-512614b147d8'
但我不敢相信我的数据库记录实际上没有更新。以前我使用 .save,但实际上没有成功,它创建了 SAVEPOINT。
我遇到麻烦的代码基本上是一个 API 端点:
cache = System::Flights::Cached.search_cache options
# update database, when the captcha is present. this way, the worker
# when updating the database can see the changes and act accordingly!
if cache && params[:captcha]
# remember, anyone can (basically) see the captcha. thus,
# this is a bit paranoid, only allow captcha update
# if the user is same! in the json, if not forgotten,
# captcha is only displayed when the user_id is equal
server_stuff = cache.server_stuff.with_indifferent_access
if server_stuff[:user_id] == current_user.id
cache.time_renewed = 10
cache.client_stuff_will_change!
cache.client_stuff ||= {}
cache.client_stuff[:captcha] = params[:captcha]
# cache.save!
cache.update_columns(client_stuff: cache.client_stuff)
end
else
# only spawn worker if there is no captcha parameter passed
spawn_search_worker({user_id: current_user.id, options: options})
end
客户可以随时到达此位置,并且将跨越工作人员。当新记录已在数据库中但 is_processed 为 false 时,worker 将退出。因此,多次调用它是可以的,这也是检查工作是否完成的一种方法。
工作人员将等待客户输入验证码。所以,我们有像 WaitableLogin 这样的类,它基本上是:
max_repeat = 3 # 14
# annul flag, if set to true, the data will not get persisted.
annul = false
while max_repeat > 0
# interval of 5 secs that worker can check the database
sleep 5
max_repeat -= 1
# break if captcha already entered by client
# seek from the database if the client has posted
# the captcha text
cache = System::Flights::Cached.search_cache options
client_stuff = nil
client_stuff = cache.client_stuff.with_indifferent_access if cache && cache.client_stuff
if client_stuff && client_stuff[:captcha]
captcha_text = client_stuff[:captcha]
airline.fill_captcha(captcha_text).finalize_login
puts "SOMEHOW I AM HERE: #{captcha_text}"
# remove all server's stuff
cache.server_stuff_will_change!
cache.server_stuff.clear
cache.save!
annul = airline.in_login_page?
end
end
因此,WaitableLogin 将检查 client_stuff 是否已更新。如果是,那么我们知道客户端已经提交了验证码(通过端点,工作人员将检查验证码是否为参数,如果有验证码字段,则更新数据库)。
然后将控制权转移回 Worker。您可以看到有很多代码在跨文件的许多代码部分使用缓存,缓存只是变量名,与它在 Rails 中的语义含义无关。
当我在浏览器上正常运行时,我看不到任何问题。事实上,即使我使用 .save,也没有 SAVEPOINT。我想,它在某处使用该 SAVEPOINT 创建了一些错误,所以我决定尝试使用 .update_columns。但是,再一次,没有成功。
这是测试之前的样子(:each) do System::Flights::Cached.delete_all end
describe "requests" do
it "should process 2a1c1i" do
cached = nil
post("/api/v1/x.json", {
access_token: CommonFlightData::ACCESS_TOKEN,
business_token: CommonFlightData::BUSINESS_TOKEN,
captcha: ""
}.merge!(CommonFlightData.oneway_1a(from: "8-9-2014")))
puts "enter the captcha: "
captcha = STDIN.gets.chomp
puts "Entered: #{captcha}"
post("/api/v1/x.json", {
access_token: CommonFlightData::ACCESS_TOKEN,
business_token: CommonFlightData::BUSINESS_TOKEN,
captcha: captcha
}.merge!(CommonFlightData.oneway_1a(from: "8-9-2014")))
sleep 10
所以我错过了什么,我累了。没有引发错误。当我在 update_columns 之后检查 .inspect 时,似乎所有内容都已更新。但是,当您在数据库中看到时,没有任何更新。
编辑:我放了 lock_version 以便我有乐观锁定(默认情况下,我认为)。结果,正如预期的那样,它被设置为 2。
编辑2:如果我在代码要求验证码时从rails控制台命令编辑,它会更新数据。所以,为什么运行 api 端点以提交验证码的 RSpec 规范不会更新该行。所有现实生活中没有原始规范的代码都被很好地执行。