midje
框架内测试的out.json
函数会产生不一致的结果。大部分时间它按预期进行检查,但有时会在其初始状态(""
)处读取async-blocker
。在检查之前,我依靠process-async
函数在(require '[[test-with-files.core :refer [with-files public-dir]])
(defn async-blocker [fun & args]
(let [chan-test (chan)]
(go (>! chan-test (apply fun args)))
(<!! chan-test)))
(defn process-async
[channel func]
(go-loop []
(when-let [response (<! channel)]
(func response)
(recur))))
(with-files [["/out.json" ""]]
(facts "About `process-async"
(let [channel (chan)
file (io/resource (str public-dir "/out.json"))
write #(spit file (str % "\n") :append true)]
(doseq [m ["m1" "m2"]] (>!! channel m))
(async-blocker process-async channel write)
(clojure.string/split-lines (slurp file)) => (just ["m1" "m2"] :in-any-order)
)
)
)
上等待。
我的方法有什么问题?
class Account < ActiveRecord::Base
before_save :encrypt_username, if: :username_changed?
before_save :encrypt_password, if: :password_changed?
def encrypt_username
crypt = ActiveSupport::MessageEncryptor.new(ENV['KEY'])
self.username = crypt.encrypt_and_sign(username)
end
def encrypt_password
crypt = ActiveSupport::MessageEncryptor.new(ENV['KEY'])
self.password = crypt.encrypt_and_sign(password)
end
def decrypted_username
crypt = ActiveSupport::MessageEncryptor.new(ENV['KEY'])
crypt.decrypt_and_verify(username)
end
def decrypted_password
crypt = ActiveSupport::MessageEncryptor.new(ENV['KEY'])
crypt.decrypt_and_verify(password)
end
end
答案 0 :(得分:1)
问题是process-async
会立即返回&#34; [...]一个通道,当收到身体的结果时
已完成&#34; (因为go-loop
只是(go (loop ...))
的语法糖,而go
立即返回)。
这意味着<!!
中的屏蔽async-blocker
几乎会立即显示一个值,go
阻止来自process-async
和async-blocker
的顺序执行未定。可能是大多数情况下process-async
的块首先执行,因为它首先被创建,但这在并发上下文中并不是很好的保证。
根据<!!
的文档&#34;如果关闭则返回nil。如果没有可用的话会阻止。&#34; 这意味着如果你可以假设(apply fun args)
的返回值是go
返回的频道,你应该可以阻止以下列方式使用<!!
:
(defn async-blocker [fun & args]
(<!! (apply fun args)))
一旦通道中有值(即go
块的返回值),这将取消阻塞。
还有其他选项可以等待另一个go
块的结果。例如,您可以在chan-test
中提供原始fun
作为参数,然后在put
中创建chan-test
块时go
中的值fun
终止。但我认为,鉴于您展示的代码,其他方法可能会更加复杂。