首页 > 解决方案 > 启动服务的正确方法,如果它没有使用shake-build运行?

问题描述

我的构建过程需要访问各种服务,例如 Postgres、Redis 和 ElasticSearch。以Postgres为例,我写了如下的“oracle”:

data PostgresVersion = PostgresVersion deriving (Show, Typeable, Eq, Hashable, Binary, NFData, Generic)
type instance RuleResult PostgresVersion = String

shakeArgs shakeOptions{..} $ do
  want [..]

  addOracle $ \PostgresVersion -> do
    fromStdout <$> cmd (AddEnv "PGPASSWORD" "REDACTED") ["psql", "-qAt", "-U", "pguser", "-h", "localhost", "dbname", "-c", "show server_version"]

除了确保 Postgres 正在运行之外,它还捕获版本号,这可能是构建过程中的额外断言。

但是,如何处理 Postgres 未运行的情况?我应该使用标准的 Haskell try/catch来处理它并启动 Postgres 吗?或者启动/停止服务是否应该超出“Shakefile”的范围?

标签: shake-build-system

解决方案


答案完全取决于您想要什么结果,但听起来您希望始终确保 Postgres 可用并且在构建期间可以访问它。在这种情况下,我会利用 Shake 脚本只是 Haskell 的事实并编写:

withPostgres :: ConnectionString -> (PostgresHandle -> IO a) -> IO a
withPostgres = written without using Shake at all

然后将您定义main为:

main = withPostgres "" $ \pg ->
    shakeArgs ... using pg

唯一的缺点是即使不需要它也将始终启动 Postgres。要仅在必要时启动它,您可以将 Postgres 的启动转换为缓存操作(最多运行一次):

rules = do
    startPostgres <- newCache $ \() -> do
        ... start Postgres here ...
        runAfter $ ... shut down Postgres if you want ...

    "*.txt" %> \out -> do
        startPostgres ()
        ... now use Postgres ...

在这两种情况下,我都会利用启动 Postgres 完全在 IO 中的事实,并使用普通catch/finally等来处理异常。如果您在Actionmonad 中,您可以使用启动 PostgresliftIO的任何操作来运行。IO

更多信息可以在 GitHub 问题中找到,该问题涵盖了类似的领域:https ://github.com/ndmitchell/shake/issues/615


推荐阅读