Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ namespace optionx::platforms::intrade_bar {
int64_t m_disconnected_domain_retry_period_ms = time_shield::MS_PER_15_SEC; ///< Disconnected host/domain recovery period.
bool m_has_balance_update = false; ///< Flag indicating if a balance update is in progress.
bool m_check_host_in_progress = false;
std::uint32_t m_consecutive_host_check_failures = 0; ///< Consecutive failed host checks while connected.
static constexpr std::uint32_t kHostCheckFailureThreshold = 2;
std::uint64_t m_balance_request_generation = 0; ///< Monotonic balance request generation.
std::uint64_t m_active_balance_request_generation = 0; ///< Currently active balance request generation.
std::uint64_t m_host_request_generation = 0; ///< Monotonic host/domain request generation.
Expand Down Expand Up @@ -414,6 +416,7 @@ namespace optionx::platforms::intrade_bar {

m_task_manager.shutdown();
invalidate_async_requests("connected");
m_consecutive_host_check_failures = 0;

LOGIT_INFO(
"Intrade Bar balance: starting connected balance polling. period_ms=",
Expand Down Expand Up @@ -444,15 +447,33 @@ namespace optionx::platforms::intrade_bar {
if (!finish_host_request(generation, "connected-host-check")) {
return;
}
if (!success) {
auto account_info = get_account_info();
if (account_info->connect) {
account_info->connect = false;
using Status = events::AccountInfoUpdateEvent::Status;
const std::string error_text("Ping to current host failed.");
LOGIT_ERROR(error_text);
notify(events::AccountInfoUpdateEvent(account_info, Status::DISCONNECTED, error_text));
if (success) {
if (m_consecutive_host_check_failures != 0) {
LOGIT_INFO(
"Intrade Bar balance: current host check recovered after failures=",
m_consecutive_host_check_failures);
}
m_consecutive_host_check_failures = 0;
return;
}

++m_consecutive_host_check_failures;
LOGIT_WARN(
"Intrade Bar balance: current host check failed. consecutive_failures=",
m_consecutive_host_check_failures,
"; disconnect_threshold=",
kHostCheckFailureThreshold);
if (m_consecutive_host_check_failures < kHostCheckFailureThreshold) {
return;
}

auto account_info = get_account_info();
if (account_info->connect) {
account_info->connect = false;
using Status = events::AccountInfoUpdateEvent::Status;
const std::string error_text("Ping to current host failed.");
LOGIT_ERROR(error_text);
notify(events::AccountInfoUpdateEvent(account_info, Status::DISCONNECTED, error_text));
}
});
});
Expand All @@ -464,6 +485,7 @@ namespace optionx::platforms::intrade_bar {

m_task_manager.shutdown();
invalidate_async_requests("disconnected");
m_consecutive_host_check_failures = 0;
LOGIT_INFO(
"Intrade Bar balance: starting disconnected host recovery. period_ms=",
m_disconnected_domain_retry_period_ms);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,10 @@ namespace optionx::platforms::intrade_bar {
LOGIT_TRACE0();

auto& client = get_http_client();
client.set_head_only(true); // Use HEAD to avoid downloading body
// Use a regular GET here. Some proxies and broker frontends handle
// HEAD-like requests inconsistently, which can produce a local 499
// even while the authenticated transport is still healthy.
client.set_head_only(false);
client.set_retry_attempts(3, time_shield::MS_PER_SEC);
client.set_timeout(5);
client.set_connect_timeout(5);
Expand All @@ -991,7 +994,11 @@ namespace optionx::platforms::intrade_bar {
bool success = response->status_code == 200;
LOGIT_PRINT_DEBUG("Current host ping check:",
" success:", success,
"; status:", response->status_code);
"; status:", response->status_code,
"; error_code:", response->error_code.value(),
"; error:", response->error_code.message(),
"; retry_attempt:", response->retry_attempt,
"; message:", response->error_message);
check_callback(success);
};

Expand Down
53 changes: 53 additions & 0 deletions tests/intrade_bar_api/intrade_bar_api_response_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,20 @@ struct LocalLoginServer {
response->write(SimpleWeb::StatusCode::success_ok, "ok");
};

server.resource["^/$"]["GET"] = [this](
std::shared_ptr<TradeHistoryHttpServer::Response> response,
std::shared_ptr<TradeHistoryHttpServer::Request>) {
++host_health_get_requests;
response->write(SimpleWeb::StatusCode::success_ok, "ok");
};

server.resource["^/$"]["HEAD"] = [this](
std::shared_ptr<TradeHistoryHttpServer::Response> response,
std::shared_ptr<TradeHistoryHttpServer::Request>) {
++host_health_head_requests;
response->write(SimpleWeb::StatusCode::client_error_not_found);
};

server.resource["^/login$"]["POST"] = [this](
std::shared_ptr<TradeHistoryHttpServer::Response> response,
std::shared_ptr<TradeHistoryHttpServer::Request>) {
Expand Down Expand Up @@ -263,6 +277,8 @@ struct LocalLoginServer {
std::atomic<int> login_requests{0};
std::atomic<int> auth_redirect_requests{0};
std::atomic<int> profile_requests{0};
std::atomic<int> host_health_get_requests{0};
std::atomic<int> host_health_head_requests{0};
std::string login_redirect;
};

Expand Down Expand Up @@ -823,6 +839,43 @@ TEST(IntradeBarLogin, MergesLoginCookiesCaseInsensitively) {
EXPECT_NE(cookies.find("challenge=fake"), std::string::npos);
}

TEST(IntradeBarHostHealth, ChecksCurrentHostWithGet) {
LocalLoginServer server;
ASSERT_TRUE(server.start());

TestPlatform platform;
HttpClientComponent http_client(platform);
RequestManager request_manager(platform, http_client);

auto auth_data = std::make_shared<AuthData>();
auth_data->host = server.host();
auth_data->auto_find_domain = false;

events::AuthDataEvent auth_event(auth_data);
request_manager.on_event(&auth_event);
http_client.get_http_client().set_retry_attempts(0, 0);

bool callback_received = false;
bool host_available = false;
request_manager.request_check_current_host_available(
[&](bool success) {
callback_received = true;
host_available = success;
});

for (int i = 0; i < 500 && !callback_received; ++i) {
http_client.process();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

EXPECT_TRUE(callback_received);
EXPECT_TRUE(host_available);
EXPECT_EQ(server.host_health_get_requests.load(), 1);
EXPECT_EQ(server.host_health_head_requests.load(), 0);

platform.shutdown();
}

TEST(IntradeBarLogin, FollowsOpaqueRedirectAndReturnsIssuedCookies) {
LocalLoginServer server;
ASSERT_TRUE(server.start());
Expand Down
Loading