From fbf97d1432ca6e6a7e9bb35a6b97c7b9dcb42b3a Mon Sep 17 00:00:00 2001 From: Moritz Kiefer Date: Wed, 30 Mar 2022 16:31:13 +0200 Subject: [PATCH] Change Canton synchronization to use the healthcheck endpoint (#13463) changelog_begin changelog_end --- .../runner_with_health_check/BUILD.bazel | 26 ++++++++++++ .../runner_with_health_check/Main.hs | 40 +++++++++++++++++++ .../BUILD.bazel | 6 ++- .../canton-test-runner.sh | 27 ------------- ledger/ledger-api-tests/conformance.bzl | 3 +- 5 files changed, 72 insertions(+), 30 deletions(-) create mode 100644 bazel_tools/client_server/runner_with_health_check/BUILD.bazel create mode 100644 bazel_tools/client_server/runner_with_health_check/Main.hs diff --git a/bazel_tools/client_server/runner_with_health_check/BUILD.bazel b/bazel_tools/client_server/runner_with_health_check/BUILD.bazel new file mode 100644 index 00000000000..75d57761f9c --- /dev/null +++ b/bazel_tools/client_server/runner_with_health_check/BUILD.bazel @@ -0,0 +1,26 @@ +# Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +load("//bazel_tools:haskell.bzl", "da_haskell_binary") + +da_haskell_binary( + name = "runner_with_health_check", + srcs = ["Main.hs"], + hackage_deps = [ + "base", + "extra", + "typed-process", + "process", + "async", + "http-client", + "http-conduit", + "http-types", + "text", + "safe", + "split", + "monad-loops", + "safe-exceptions", + ], + visibility = ["//visibility:public"], + deps = ["//libs-haskell/da-hs-base"], +) diff --git a/bazel_tools/client_server/runner_with_health_check/Main.hs b/bazel_tools/client_server/runner_with_health_check/Main.hs new file mode 100644 index 00000000000..919d18818a5 --- /dev/null +++ b/bazel_tools/client_server/runner_with_health_check/Main.hs @@ -0,0 +1,40 @@ +-- Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module Main(main) where + +import Data.Maybe (isJust) +import System.Environment +import Control.Exception.Safe +import Control.Monad.Loops (untilJust) +import System.Process.Typed +import Data.List.Split (splitOn) +import Control.Monad (guard, when) +import Network.HTTP.Client (parseUrlThrow) +import qualified Network.HTTP.Simple as HTTP +import Control.Concurrent +import System.Info.Extra +import System.Process (terminateProcess) + +main :: IO () +main = do + [clientExe, clientArgs, serverExe, serverArgs, runnerArgs] <- getArgs + let splitArgs = filter (/= "") . splitOn " " + let serverProc = proc serverExe (splitArgs serverArgs) + healthPort : _ :: [Int] <- pure $ reverse $ map read $ splitArgs runnerArgs + withProcessTerm serverProc $ \ph -> do + waitForHealthcheck (threadDelay 500000) healthPort + runProcess_ (proc clientExe (splitArgs clientArgs)) + -- See the comment on DA.Daml.Helper.Util.withProcessWait_' + when isWindows (terminateProcess $ unsafeProcessHandle ph) + +waitForHealthcheck :: IO () -> Int -> IO () +waitForHealthcheck sleep port = do + request <- parseUrlThrow $ "http://localhost:" <> show port <> "/health" + untilJust $ do + r <- tryJust (\e -> guard (isIOException e || isHttpException e)) $ HTTP.httpNoBody request + case r of + Left _ -> sleep *> pure Nothing + Right _ -> pure $ Just () + where isIOException e = isJust (fromException e :: Maybe IOException) + isHttpException e = isJust (fromException e :: Maybe HTTP.HttpException) diff --git a/ledger/ledger-api-test-tool-on-canton/BUILD.bazel b/ledger/ledger-api-test-tool-on-canton/BUILD.bazel index 617a13c72fd..f8bd1065cac 100644 --- a/ledger/ledger-api-test-tool-on-canton/BUILD.bazel +++ b/ledger/ledger-api-test-tool-on-canton/BUILD.bazel @@ -60,6 +60,7 @@ conformance_test( "@jq_dev_env//:jq", "@bazel_tools//tools/jdk", ], + extra_runner_args = ["7000"], lf_versions = [ "default", "latest", @@ -70,7 +71,7 @@ conformance_test( 5031, 5041, ], - runner = "@//bazel_tools/client_server/runner_with_port_check", + runner = "@//bazel_tools/client_server/runner_with_health_check", server = ":canton-test-runner-with-dependencies", server_args = [], test_tool_args = [ @@ -121,6 +122,7 @@ conformance_test( "@jq_dev_env//:jq", "@bazel_tools//tools/jdk", ], + extra_runner_args = ["7000"], lf_versions = [ "default", "latest", @@ -131,7 +133,7 @@ conformance_test( 5031, 5041, ], - runner = "@//bazel_tools/client_server/runner_with_port_check", + runner = "@//bazel_tools/client_server/runner_with_health_check", server = ":canton-test-runner-with-dependencies", test_tool_args = [ "--verbose", diff --git a/ledger/ledger-api-test-tool-on-canton/canton-test-runner.sh b/ledger/ledger-api-test-tool-on-canton/canton-test-runner.sh index a154f7a2f84..c42407e02a2 100755 --- a/ledger/ledger-api-test-tool-on-canton/canton-test-runner.sh +++ b/ledger/ledger-api-test-tool-on-canton/canton-test-runner.sh @@ -15,29 +15,6 @@ CANTON_COMMAND=( "--bootstrap=$(rlocation com_github_digital_asset_daml/ledger/ledger-api-test-tool-on-canton/bootstrap.canton)" ) -PARTICIPANT_1_HOST=localhost -PARTICIPANT_1_MONITORING_PORT=7000 - -TIMEOUT=60 - -function wait_until() { - local start - - start="$(date +%s)" - while true; do - if [[ "$(("$(date +%s)" - start))" -gt "$TIMEOUT" ]]; then - echo >&2 "Timed out after ${TIMEOUT} seconds." - return 1 - fi - - if "$@" >&/dev/null; then - return 0 - fi - - sleep 1 - done -} - command=("${CANTON_COMMAND[@]}" "$@") export UNIQUE_CONTRACT_KEYS="$(rlocation com_github_digital_asset_daml/ledger/ledger-api-test-tool-on-canton/unique-contract-keys.conf)" @@ -77,8 +54,4 @@ function stop() { trap stop EXIT INT TERM -wait_until curl -fsS "http://${PARTICIPANT_1_HOST}:${PARTICIPANT_1_MONITORING_PORT}/health" - -echo >&2 'Canton is up and running.' - wait "$pid" diff --git a/ledger/ledger-api-tests/conformance.bzl b/ledger/ledger-api-tests/conformance.bzl index b13781146c6..b73cabf080a 100644 --- a/ledger/ledger-api-tests/conformance.bzl +++ b/ledger/ledger-api-tests/conformance.bzl @@ -18,6 +18,7 @@ def conformance_test( test_tool_args = [], tags = [], runner = "@//bazel_tools/client_server/runner_with_port_check", + extra_runner_args = [], lf_versions = ["default"], flaky = False): for lf_version in lf_versions_aggregate(lf_versions): @@ -27,7 +28,7 @@ def conformance_test( client_server_test( name = test_name, runner = runner, - runner_args = ["%s" % port for port in ports], + runner_args = ["%s" % port for port in ports] + extra_runner_args, timeout = "long", client = "//ledger/ledger-api-tests/tool:tool-%s" % lf_version, client_args = test_tool_args + ["localhost:%s" % port for port in ports],