Skip to content

Commit

Permalink
feat(server): adding version monoitoring task
Browse files Browse the repository at this point in the history
Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
  • Loading branch information
boazsade committed Dec 21, 2022
1 parent 2386b02 commit 79ed892
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ add_library(dragonfly_lib channel_slice.cc command_registry.cc
zset_family.cc version.cc bitops_family.cc container_utils.cc
serializer_commons.cc journal/serializer.cc journal/executor.cc)

cxx_link(dragonfly_lib dfly_transaction dfly_facade redis_lib strings_lib html_lib
cxx_link(dragonfly_lib dfly_transaction dfly_facade redis_lib strings_lib html_lib http_client_lib
absl::random_random TRDP::jsoncons zstd TRDP::lz4)

add_library(dfly_test_lib test_utils.cc)
Expand Down
124 changes: 123 additions & 1 deletion src/server/dfly_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include <mimalloc.h>
#include <signal.h>

#include <regex>

#include "base/init.h"
#include "base/proc_util.h" // for GetKernelVersion
#include "facade/dragonfly_listener.h"
Expand All @@ -28,6 +30,7 @@
#include "strings/human_readable.h"
#include "util/accept_server.h"
#include "util/epoll/epoll_pool.h"
#include "util/http/http_client.h"
#include "util/uring/uring_pool.h"
#include "util/varz.h"

Expand Down Expand Up @@ -96,6 +99,122 @@ namespace dfly {

namespace {

using util::http::TlsClient;

const std::string_view kInvalidVersion{"unknown version"};

std::string GetVersionString(const std::string& from) {
// The server sends a message such as {"latest": "0.12.0"}
const auto reg_match_expr = R"(\{\"latest"\:[ \t]*\"([0-9]+\.[0-9]+\.[0-9]+)\"\})";
VLOG(1) << "checking version '" << from << "'";
auto const regex = std::regex(reg_match_expr);
std::smatch match;
if (std::regex_match(from, match, regex) && match.size() > 1) {
// the second entry is the match to the group that holds the version string
return match[1].str();
} else {
return std::string{kInvalidVersion};
}
}

std::string GetRemoteVersion(ProactorBase* proactor, SSL_CTX* ssl_context, const std::string host,
std::string_view service, const std::string& resource) {
namespace bh = boost::beast::http;
using ResponseType = bh::response<bh::string_body>;

TlsClient http_client{proactor};

http_client.set_connect_timeout_ms(2000);
auto version = proactor->Await([&] {
if (auto ec = http_client.Connect(host, service, ssl_context); !ec) {
bh::request<bh::string_body> req{bh::verb::get, resource, 11 /*http 1.1*/};
req.set(bh::field::host, host.c_str());
ResponseType res;
if (auto ec = http_client.Send(req, &res); !ec) {
VLOG(1) << "successfully got response from HTTP GET for host " << host << ":" << service
<< "/" << resource << " response code is " << res.result();

if (res.result() == bh::status::ok) {
const auto& body = res.body();
return GetVersionString(body);
}
} else {
LOG(WARNING) << "failed to process send HTTP GET to " << host << "@" << service
<< " at resource '" << resource << "'";
}
} else {
LOG(WARNING) << "failed to connect: " << ec.message();
}
return std::string{kInvalidVersion};
});

return version;
}

struct VersionMonitor {
fibers_ext::Fiber version_fiber_;
fibers_ext::Done monitor_ver_done_;
ProactorPool* proactor_pool_ = nullptr;

explicit VersionMonitor(ProactorPool* pp) : proactor_pool_{pp} {
}

void Run() {
version_fiber_ = proactor_pool_->GetNextProactor()->LaunchFiber([this] { RunTask(); });
}

void Shutdown() {
monitor_ver_done_.Notify();
if (version_fiber_.IsJoinable()) {
version_fiber_.Join();
}
}

private:
void RunTask();
};

void VersionMonitor::RunTask() {
const auto loop_sleep_time = std::chrono::hours(24); // every 24 hours

const std::string host_name = "run-stage-43h632k3xq-ew.a.run.app";
const std::string_view port = "443";
const std::string resource = "/v1";
const std::string dev_version_name = "dev";

// Don't run in dev environment - i.e. where we don't build with
// real version number
if (kGitTag == dev_version_name) {
return;
}

SSL_CTX* context = TlsClient::CreateSslContext();
if (!context) {
LOG(WARNING) << "failed to create SSL context - cannot run version monitoring";
return;
}

auto CheckForNewerVersion = [&]() {
auto remote_version =
GetRemoteVersion(proactor_pool_->GetNextProactor(), context, host_name, port, resource);
if (remote_version != kGitTag) {
LOG_FIRST_N(INFO, 1) << "Your current version '" << kGitTag
<< "' is not the latest version. A newer version '" << remote_version
<< "' is now available. Please consider an update.";
}
};

CheckForNewerVersion();
while (true) {
if (monitor_ver_done_.WaitFor(loop_sleep_time)) {
TlsClient::FreeContext(context);
VLOG(1) << "finish running version monitor task";
return;
}
CheckForNewerVersion();
}
}

enum class TermColor { kDefault, kRed, kGreen, kYellow };
// Returns the ANSI color code for the given color. TermColor::kDefault is
// an invalid input.
Expand Down Expand Up @@ -195,9 +314,12 @@ bool RunEngine(ProactorPool* pool, AcceptServer* acceptor) {
acceptor->AddListener(mc_port, new Listener{Protocol::MEMCACHE, &service});
}

VersionMonitor version_monitor{pool};

acceptor->Run();
version_monitor.Run();
acceptor->Wait();

version_monitor.Shutdown();
service.Shutdown();

if (unlink_uds) {
Expand Down

0 comments on commit 79ed892

Please sign in to comment.