TLDR:我如何启动一个“一次性使用”的远程-prepl连接,该连接执行单个命令,获取返回值,然后释放所有使用的资源?
我在Slack上询问了这个问题,但没有收到回复。在实际情况中,这通常不是一个大问题,但我一直在为此烦恼,所以我决定更正式地记录在这里。
我曾以为短生命周期的远程-prepl客户端是一个预期的使用方式。它应该允许用户连接到远程系统,执行某个操作,获取返回值,然后断开连接。
以下是一些我找到的示例代码:
https://github.com/Olical/how-to-be-a-repl-sorcerer/blob/b6bd530f3d0c6b165248d980d7ce6cd28e8da51f/src/sorcery/main.clj#L20
稍有修改
(ns prepl-question
(:require [clojure.core.server :as server])
(:import [java.io PipedReader PipedWriter]))
(def srv
(server/start-server {:accept 'clojure.core.server/io-prepl
:port 0
:name "srv"}))
(defn remote-eval [code]
(with-open [reader (PipedReader.)
writer (PipedWriter.)]
(.connect reader writer)
(let [result! (promise)]
(future
(server/remote-prepl
"localhost" (.getLocalPort srv)
reader
(fn [msg]
(deliver result! msg)))
(println "DONE"))
(.write writer code)
(.flush writer)
@result!
;; doesn't print "DONE"
(let [r @result!]
(.close reader)
(.close writer)
;;(.write writer ":repl/quit\n") ;; also tried this
;;(.flush writer)
r))))
(remote-eval "(+ 1 2 3)")
我发现无法通过关闭所用的流来获取“ 完成”输出,这标志着停止prepl线程循环。无论关闭流的组合多么复杂,都无法实现。
稍加查看远程-prepl的源代码,它似乎会在这一行调用关闭reader的操作,但它将在reader已经关闭时调用。但至少在上述示例中,我发现当第二次调用close时,这会导致事情永远挂起。我猜这与https://stackoverflow.com/a/45703662中描述的问题有关,与PipedReader/Writer的设置有关。
但我不确定这是否可以被认为是prepl代码中的错误,或者是我使用方法不对。