diff options
author | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2018-07-13 17:10:01 -0400 |
---|---|---|
committer | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2018-07-13 17:10:01 -0400 |
commit | 77ab40c05f28c6c0afbc84bb72375a9867f79ecb (patch) | |
tree | acd2fc8198419a2b60bbd50abf781c7c87e11dbd | |
parent | 5a7537b07dbf7d8db74531632dc06883042b4234 (diff) | |
download | mongo-77ab40c05f28c6c0afbc84bb72375a9867f79ecb.tar.gz |
SERVER-35692 Add support to an optional re-registration bool in metrics response
-rw-r--r-- | jstests/free_mon/free_mon_register.js | 4 | ||||
-rw-r--r-- | jstests/free_mon/free_mon_register_cmd.js | 4 | ||||
-rw-r--r-- | jstests/free_mon/free_mon_register_resend.js | 28 | ||||
-rw-r--r-- | jstests/free_mon/free_mon_rs_register.js | 3 | ||||
-rw-r--r-- | jstests/free_mon/free_mon_rs_resend.js | 66 | ||||
-rw-r--r-- | jstests/free_mon/libs/free_mon.js | 11 | ||||
-rw-r--r-- | jstests/free_mon/libs/mock_http_server.py | 37 | ||||
-rw-r--r-- | src/mongo/db/free_mon/free_mon_controller_test.cpp | 88 | ||||
-rw-r--r-- | src/mongo/db/free_mon/free_mon_processor.cpp | 60 | ||||
-rw-r--r-- | src/mongo/db/free_mon/free_mon_processor.h | 24 | ||||
-rw-r--r-- | src/mongo/db/free_mon/free_mon_protocol.idl | 9 |
11 files changed, 300 insertions, 34 deletions
diff --git a/jstests/free_mon/free_mon_register.js b/jstests/free_mon/free_mon_register.js index d0d29f114de..6d1ae50274a 100644 --- a/jstests/free_mon/free_mon_register.js +++ b/jstests/free_mon/free_mon_register.js @@ -31,7 +31,7 @@ load("jstests/free_mon/libs/free_mon.js"); const last_register = mock_web.query("last_register"); print(tojson(last_register)); - assert.eq(last_register.version, 1); + assert.eq(last_register.version, 2); assert.gt(new Date().setTime(last_register.localTime["$date"]), localTime); assert.eq(last_register.payload.buildInfo.bits, 64); assert.eq(last_register.payload.buildInfo.ok, 1); @@ -44,7 +44,7 @@ load("jstests/free_mon/libs/free_mon.js"); const last_metrics = mock_web.query("last_metrics"); print(tojson(last_metrics)); - assert.eq(last_metrics.version, 1); + assert.eq(last_metrics.version, 2); assert.gt(new Date().setTime(last_metrics.localTime["$date"]), localTime); MongoRunner.stopMongod(conn); diff --git a/jstests/free_mon/free_mon_register_cmd.js b/jstests/free_mon/free_mon_register_cmd.js index 6eb0c1f9c69..35fdc9397af 100644 --- a/jstests/free_mon/free_mon_register_cmd.js +++ b/jstests/free_mon/free_mon_register_cmd.js @@ -41,7 +41,7 @@ load("jstests/free_mon/libs/free_mon.js"); const last_register = mock_web.query("last_register"); print(tojson(last_register)); - assert.eq(last_register.version, 1); + assert.eq(last_register.version, 2); assert.eq(last_register.payload.buildInfo.bits, 64); assert.eq(last_register.payload.buildInfo.ok, 1); assert.eq(last_register.payload.storageEngine.readOnly, false); @@ -52,7 +52,7 @@ load("jstests/free_mon/libs/free_mon.js"); const last_metrics = mock_web.query("last_metrics"); print(tojson(last_metrics)); - assert.eq(last_metrics.version, 1); + assert.eq(last_metrics.version, 2); assert.commandWorked(conn.adminCommand({setFreeMonitoring: 1, action: "disable"})); diff --git a/jstests/free_mon/free_mon_register_resend.js b/jstests/free_mon/free_mon_register_resend.js new file mode 100644 index 00000000000..de98e038ac6 --- /dev/null +++ b/jstests/free_mon/free_mon_register_resend.js @@ -0,0 +1,28 @@ +// Validate resend registration works in a replica set +// +load("jstests/free_mon/libs/free_mon.js"); + +(function() { + 'use strict'; + + let mock_web = new FreeMonWebServer(FAULT_RESEND_REGISTRATION_ONCE); + + mock_web.start(); + + let options = { + setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), + enableFreeMonitoring: "on", + verbose: 1, + }; + + const conn = MongoRunner.runMongod(options); + assert.neq(null, conn, 'mongod was unable to start up'); + + WaitForRegistration(conn); + + mock_web.waitRegisters(2); + + MongoRunner.stopMongod(conn); + + mock_web.stop(); +})(); diff --git a/jstests/free_mon/free_mon_rs_register.js b/jstests/free_mon/free_mon_rs_register.js index 1c518456a2f..acbdab3301c 100644 --- a/jstests/free_mon/free_mon_rs_register.js +++ b/jstests/free_mon/free_mon_rs_register.js @@ -15,6 +15,7 @@ load("jstests/free_mon/libs/free_mon.js"); }; const rst = new ReplSetTest({nodes: 2, nodeOptions: options}); + rst.startSet(); rst.initiate(); rst.awaitReplication(); @@ -33,7 +34,7 @@ load("jstests/free_mon/libs/free_mon.js"); const last_register = mock_web.query("last_register"); print(tojson(last_register)); - assert.eq(last_register.version, 1); + assert.eq(last_register.version, 2); assert.eq(last_register.payload.buildInfo.bits, 64); assert.eq(last_register.payload.buildInfo.ok, 1); assert.eq(last_register.payload.storageEngine.readOnly, false); diff --git a/jstests/free_mon/free_mon_rs_resend.js b/jstests/free_mon/free_mon_rs_resend.js new file mode 100644 index 00000000000..464caf396e5 --- /dev/null +++ b/jstests/free_mon/free_mon_rs_resend.js @@ -0,0 +1,66 @@ +// Validate resend registration works in a replica set +// +load("jstests/free_mon/libs/free_mon.js"); + +(function() { + 'use strict'; + + let mock_web = new FreeMonWebServer(FAULT_RESEND_REGISTRATION_AT_3); + let mock_web_sec = new FreeMonWebServer(FAULT_RESEND_REGISTRATION_ONCE, true); + + mock_web.start(); + mock_web_sec.start(); + + const rst = new ReplSetTest({ + name: "free_mon_rs_register", + nodes: [ + { + setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), + verbose: 1, + }, + { + setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web_sec.getURL(), + verbose: 1, + } + ] + }); + + rst.startSet(); + rst.initiate(); + rst.awaitReplication(); + + sleep(10 * 1000); + assert.eq(0, mock_web.queryStats().registers, "mongod registered without enabling free_mod"); + assert.eq( + 0, mock_web_sec.queryStats().registers, "mongod registered without enabling free_mod"); + + assert.commandWorked(rst.getPrimary().adminCommand({setFreeMonitoring: 1, action: "enable"})); + WaitForRegistration(rst.getPrimary()); + + mock_web.waitRegisters(1); + mock_web_sec.waitRegisters(1); + + assert.eq(FreeMonGetServerStatus(rst.getPrimary()).state, 'enabled'); + assert.eq(FreeMonGetServerStatus(rst.getSecondary()).state, 'enabled'); + + mock_web.waitRegisters(2); + mock_web_sec.waitRegisters(2); + mock_web_sec.disableFaults(); + + // Trigger resend on the secondary only + mock_web_sec.enableFaults(); + mock_web_sec.waitFaults(1); + mock_web_sec.waitRegisters(3); + + // Double check registers were as expected + const stats = mock_web.queryStats(); + assert.eq(stats.registers, 2); + + const stats_sec = mock_web_sec.queryStats(); + assert.gte(stats_sec.registers, 3); + + rst.stopSet(); + + mock_web.stop(); + mock_web_sec.stop(); +})(); diff --git a/jstests/free_mon/libs/free_mon.js b/jstests/free_mon/libs/free_mon.js index 3cb9f90e364..74da57b3e6b 100644 --- a/jstests/free_mon/libs/free_mon.js +++ b/jstests/free_mon/libs/free_mon.js @@ -9,6 +9,8 @@ const FAULT_FAIL_REGISTER = "fail_register"; const FAULT_INVALID_REGISTER = "invalid_register"; const FAULT_HALT_METRICS_5 = "halt_metrics_5"; const FAULT_PERMANENTLY_DELETE_AFTER_3 = "permanently_delete_after_3"; +const FAULT_RESEND_REGISTRATION_AT_3 = "resend_registration_at_3"; +const FAULT_RESEND_REGISTRATION_ONCE = "resend_registration_once"; const DISABLE_FAULTS = "disable_faults"; const ENABLE_FAULTS = "enable_faults"; @@ -175,10 +177,11 @@ class FreeMonWebServer { */ waitRegisters(count) { const qs = this.queryStats.bind(this); + const port = this.port; // Wait for registration to occur assert.soon(function() { const stats = qs(); - print("QS : " + tojson(stats)); + print("w" + port + "| waiting for registers >= (" + count + ") QS : " + tojson(stats)); return stats.registers >= count; }, "Failed to web server register", 60 * 1000); } @@ -190,10 +193,11 @@ class FreeMonWebServer { */ waitMetrics(count) { const qs = this.queryStats.bind(this); + const port = this.port; // Wait for metrics uploads to occur assert.soon(function() { const stats = qs(); - print("QS : " + tojson(stats)); + print("w" + port + "| waiting for metrics >= (" + count + ") QS : " + tojson(stats)); return stats.metrics >= count; }, "Failed to web server metrics", 60 * 1000); } @@ -205,10 +209,11 @@ class FreeMonWebServer { */ waitFaults(count) { const qs = this.queryStats.bind(this); + const port = this.port; // Wait for faults to be triggered assert.soon(function() { const stats = qs(); - print("QS : " + tojson(stats)); + print("w" + port + "| waiting for faults >= (" + count + ") QS : " + tojson(stats)); return stats.faults >= count; }, "Failed to web server faults", 60 * 1000); } diff --git a/jstests/free_mon/libs/mock_http_server.py b/jstests/free_mon/libs/mock_http_server.py index 2005575463c..f6ce1a39299 100644 --- a/jstests/free_mon/libs/mock_http_server.py +++ b/jstests/free_mon/libs/mock_http_server.py @@ -36,12 +36,20 @@ FAULT_HALT_METRICS_5 = "halt_metrics_5" """Fault which causes metrics to return permanentlyDelete = true after 3 uploads.""" FAULT_PERMANENTLY_DELETE_AFTER_3 = "permanently_delete_after_3" +"""Fault which causes metrics to trigger resentRegistration at 3 uploads.""" +FAULT_RESEND_REGISTRATION_AT_3 = "resend_registration_at_3" + +"""Fault which causes metrics to trigger resentRegistration once.""" +FAULT_RESEND_REGISTRATION_ONCE = "resend_registration_once" + # List of supported fault types SUPPORTED_FAULT_TYPES = [ FAULT_FAIL_REGISTER, FAULT_INVALID_REGISTER, FAULT_HALT_METRICS_5, FAULT_PERMANENTLY_DELETE_AFTER_3, + FAULT_RESEND_REGISTRATION_AT_3, + FAULT_RESEND_REGISTRATION_ONCE, ] # Supported POST URL types @@ -117,7 +125,7 @@ class FreeMonHandler(http.server.BaseHTTPRequestHandler): data = bson.BSON.encode({ 'version': bson.int64.Int64(42), 'haltMetricsUploading': False, - 'id': 'mock123', + 'id': '', 'informationalURL': 'http://www.example.com/123', 'message': 'Welcome to the Mock Free Monitoring Endpoint', 'reportingInterval': bson.int64.Int64(1), @@ -177,12 +185,37 @@ You can disable monitoring at any time by running db.disableFreeMonitoring().""" 'reportingInterval': bson.int64.Int64(1), 'message': 'Thanks for all the metrics', }) + elif not disable_faults and \ + stats.metrics_calls > 3 and \ + stats.fault_calls < 1 and fault_type == FAULT_RESEND_REGISTRATION_ONCE: + stats.fault_calls += 1 + data = bson.BSON.encode({ + 'version': bson.int64.Int64(2), + 'haltMetricsUploading': False, + 'permanentlyDelete': False, + 'id': 'mock123', + 'reportingInterval': bson.int64.Int64(1), + 'message': 'Thanks for all the metrics', + 'resendRegistration' : True, + }) + elif not disable_faults and \ + stats.metrics_calls == 3 and fault_type == FAULT_RESEND_REGISTRATION_AT_3: + stats.fault_calls += 1 + data = bson.BSON.encode({ + 'version': bson.int64.Int64(2), + 'haltMetricsUploading': False, + 'permanentlyDelete': False, + 'id': 'mock123', + 'reportingInterval': bson.int64.Int64(1), + 'message': 'Thanks for all the metrics', + 'resendRegistration' : True, + }) else: data = bson.BSON.encode({ 'version': bson.int64.Int64(1), 'haltMetricsUploading': False, 'permanentlyDelete': False, - 'id': 'mock123', + 'id': '', 'reportingInterval': bson.int64.Int64(1), 'message': 'Thanks for all the metrics', }) diff --git a/src/mongo/db/free_mon/free_mon_controller_test.cpp b/src/mongo/db/free_mon/free_mon_controller_test.cpp index 76ba859fdee..43481e870e4 100644 --- a/src/mongo/db/free_mon/free_mon_controller_test.cpp +++ b/src/mongo/db/free_mon/free_mon_controller_test.cpp @@ -228,6 +228,8 @@ public: bool haltMetrics{false}; bool fail2MetricsUploads{false}; bool permanentlyDeleteAfter3{false}; + + bool resendRegistrationAfter3{false}; }; explicit FreeMonNetworkInterfaceMock(executor::ThreadPoolTaskExecutor* threadPool, @@ -333,6 +335,10 @@ public: resp.setPermanentlyDelete(true); } + if (_options.resendRegistrationAfter3 && _metrics.loadRelaxed() == 3) { + resp.setResendRegistration(true); + } + return resp; } @@ -551,6 +557,29 @@ TEST(FreeMonProcessorTest, TestRegistrationResponseValidation) { << "reportingInterval" << 30 * 60 * 60 * 24LL)))); + // Positive: version 2 + ASSERT_OK(FreeMonProcessor::validateRegistrationResponse(FreeMonRegistrationResponse::parse( + IDLParserErrorContext("foo"), + BSON("version" << 2LL << "haltMetricsUploading" << false << "id" + << "mock123" + << "informationalURL" + << "http://www.example.com/123" + << "message" + << "msg456" + << "reportingInterval" + << 1LL)))); + + // Positive: empty registration id string + ASSERT_OK(FreeMonProcessor::validateRegistrationResponse(FreeMonRegistrationResponse::parse( + IDLParserErrorContext("foo"), + BSON("version" << 1LL << "haltMetricsUploading" << false << "id" + << "" + << "informationalURL" + << "http://www.example.com/123" + << "message" + << "msg456" + << "reportingInterval" + << 1LL)))); // Negative: bad protocol version ASSERT_NOT_OK(FreeMonProcessor::validateRegistrationResponse(FreeMonRegistrationResponse::parse( @@ -652,7 +681,38 @@ TEST(FreeMonProcessorTest, TestMetricsResponseValidation) { << "reportingInterval" << 1LL)))); - // max reporting interval + // Positive: Support version 2 + ASSERT_OK(FreeMonProcessor::validateMetricsResponse(FreeMonMetricsResponse::parse( + IDLParserErrorContext("foo"), + + BSON("version" << 2LL << "haltMetricsUploading" << false << "permanentlyDelete" << false + << "id" + << "mock123" + << "informationalURL" + << "http://www.example.com/123" + << "message" + << "msg456" + << "reportingInterval" + << 1LL)))); + + // Positive: Add resendRegistration + ASSERT_OK(FreeMonProcessor::validateMetricsResponse(FreeMonMetricsResponse::parse( + IDLParserErrorContext("foo"), + + BSON("version" << 2LL << "haltMetricsUploading" << false << "permanentlyDelete" << false + << "id" + << "mock123" + << "informationalURL" + << "http://www.example.com/123" + << "message" + << "msg456" + << "reportingInterval" + << 1LL + << "resendRegistration" + << true)))); + + + // Positive: max reporting interval ASSERT_OK(FreeMonProcessor::validateMetricsResponse(FreeMonMetricsResponse::parse( IDLParserErrorContext("foo"), @@ -1192,6 +1252,28 @@ TEST_F(FreeMonControllerTest, TestPreRegistrationMetricBatching) { ASSERT_EQ(controller.network->getLastMetrics().nFields(), 2); } +// Positive: resend registration in metrics response +TEST_F(FreeMonControllerTest, TestResendRegistration) { + FreeMonNetworkInterfaceMock::Options opts; + opts.resendRegistrationAfter3 = true; + + ControllerHolder controller(_mockThreadPool.get(), opts); + + controller.start(RegistrationType::RegisterAfterOnTransitionToPrimary); + + ASSERT_OK(controller->registerServerCommand(Milliseconds::min())); + + controller->turnCrankForTest(Turner().registerServer().registerCommand().collect(2)); + + ASSERT_TRUE(!FreeMonStorage::read(_opCtx.get()).get().getRegistrationId().empty()); + + controller->turnCrankForTest( + Turner().metricsSend(3).collect(3).registerCommand().metricsSend(1)); + + ASSERT_EQ(controller.registerCollector->count(), 2UL); + ASSERT_GTE(controller.metricsCollector->count(), 4UL); +} + #if 0 // Negative: Test metrics buffers on failure, and retries and ensure 2 metrics occurs after a blip // of an error @@ -1372,13 +1454,13 @@ TEST_F(FreeMonControllerRSTest, StepdownDuringRegistration) { // Finish registration controller->turnCrankForTest(1); - controller->turnCrankForTest(Turner().metricsSend().collect(1)); + controller->turnCrankForTest(Turner().metricsSend().collect(2)); // Registration cannot write back to the local store so remain in pending ASSERT_TRUE(FreeMonStorage::read(_opCtx.get()).get().getState() == StorageStateEnum::pending); ASSERT_EQ(controller.registerCollector->count(), 1UL); - ASSERT_EQ(controller.metricsCollector->count(), 2UL); + ASSERT_EQ(controller.metricsCollector->count(), 3UL); } // Negative: Tricky: Primary becomes secondary during metrics send diff --git a/src/mongo/db/free_mon/free_mon_processor.cpp b/src/mongo/db/free_mon/free_mon_processor.cpp index 6e73596b8a1..2c1452a8738 100644 --- a/src/mongo/db/free_mon/free_mon_processor.cpp +++ b/src/mongo/db/free_mon/free_mon_processor.cpp @@ -52,7 +52,8 @@ namespace mongo { namespace { -constexpr auto kProtocolVersion = 1; +constexpr auto kMinProtocolVersion = 1; +constexpr auto kMaxProtocolVersion = 2; constexpr auto kStorageVersion = 1; constexpr auto kRegistrationIdMaxLength = 4096; @@ -269,13 +270,13 @@ void FreeMonProcessor::readState(OperationContext* opCtx) { _lastReadState = state; if (state.is_initialized()) { - invariant(state.get().getVersion() == kProtocolVersion); + invariant(state.get().getVersion() == kStorageVersion); _state = state.get(); } else if (!state.is_initialized()) { // Default the state auto state = _state.synchronize(); - state->setVersion(kProtocolVersion); + state->setVersion(kStorageVersion); state->setState(StorageStateEnum::disabled); state->setRegistrationId(""); state->setInformationalURL(""); @@ -411,7 +412,7 @@ void FreeMonProcessor::doCommandRegister(Client* client, req.setId(regid); } - req.setVersion(kProtocolVersion); + req.setVersion(kMaxProtocolVersion); req.setLocalTime(client->getServiceContext()->getPreciseClockSource()->now()); @@ -431,6 +432,7 @@ void FreeMonProcessor::doCommandRegister(Client* client, // Record that the registration is pending _state->setState(StorageStateEnum::pending); + _registrationStatus = FreeMonRegistrationStatus::kPending; writeState(client); @@ -451,12 +453,14 @@ void FreeMonProcessor::doCommandRegister(Client* client, Status FreeMonProcessor::validateRegistrationResponse(const FreeMonRegistrationResponse& resp) { // Any validation failure stops registration from proceeding to upload - if (resp.getVersion() != kProtocolVersion) { + if (!(resp.getVersion() >= kMinProtocolVersion && resp.getVersion() <= kMaxProtocolVersion)) { return Status(ErrorCodes::FreeMonHttpPermanentFailure, str::stream() - << "Unexpected registration response protocol version, expected '" - << kProtocolVersion - << "', received '" + << "Unexpected registration response protocol version, expected (" + << kMinProtocolVersion + << ", " + << kMaxProtocolVersion + << "), received '" << resp.getVersion() << "'"); } @@ -525,11 +529,13 @@ void FreeMonProcessor::notifyPendingRegisters(const Status s) { Status FreeMonProcessor::validateMetricsResponse(const FreeMonMetricsResponse& resp) { // Any validation failure stops registration from proceeding to upload - if (resp.getVersion() != kProtocolVersion) { + if (!(resp.getVersion() >= kMinProtocolVersion && resp.getVersion() <= kMaxProtocolVersion)) { return Status(ErrorCodes::FreeMonHttpPermanentFailure, - str::stream() << "Unexpected metrics response protocol version, expected '" - << kProtocolVersion - << "', received '" + str::stream() << "Unexpected metrics response protocol version, expected (" + << kMinProtocolVersion + << ", " + << kMaxProtocolVersion + << "), received '" << resp.getVersion() << "'"); } @@ -598,7 +604,7 @@ void FreeMonProcessor::doAsyncRegisterComplete( // Our request is no longer in-progress so delete it _futureRegistrationResponse.reset(); - if (_state->getState() != StorageStateEnum::pending) { + if (_registrationStatus != FreeMonRegistrationStatus::kPending) { notifyPendingRegisters(Status(ErrorCodes::BadValue, "Registration was canceled")); return; @@ -612,6 +618,7 @@ void FreeMonProcessor::doAsyncRegisterComplete( // Disable on any error _state->setState(StorageStateEnum::disabled); + _registrationStatus = FreeMonRegistrationStatus::kDisabled; // Persist state writeState(client); @@ -642,6 +649,8 @@ void FreeMonProcessor::doAsyncRegisterComplete( state->setState(StorageStateEnum::enabled); } + _registrationStatus = FreeMonRegistrationStatus::kEnabled; + // Persist state writeState(client); @@ -663,7 +672,7 @@ void FreeMonProcessor::doAsyncRegisterFail( // Our request is no longer in-progress so delete it _futureRegistrationResponse.reset(); - if (_state->getState() != StorageStateEnum::pending) { + if (_registrationStatus != FreeMonRegistrationStatus::kPending) { notifyPendingRegisters(Status(ErrorCodes::BadValue, "Registration was canceled")); return; @@ -689,6 +698,7 @@ void FreeMonProcessor::doCommandUnregister( readState(client); _state->setState(StorageStateEnum::disabled); + _registrationStatus = FreeMonRegistrationStatus::kDisabled; writeState(client); @@ -733,16 +743,18 @@ std::string compressMetrics(MetricsBuffer& buffer) { void FreeMonProcessor::doMetricsSend(Client* client) { readState(client); - if (_state->getState() != StorageStateEnum::enabled) { + // Only continue metrics send if the local disk state (in-case user deleted local document) + // and in-memory status both say to continue. + if (_registrationStatus != FreeMonRegistrationStatus::kEnabled || + _state->getState() != StorageStateEnum::enabled) { // If we are recently disabled, then stop sending metrics return; } // Build outbound request FreeMonMetricsRequest req; - invariant(!_state->getRegistrationId().empty()); - req.setVersion(kProtocolVersion); + req.setVersion(kMaxProtocolVersion); req.setLocalTime(client->getServiceContext()->getPreciseClockSource()->now()); req.setEncoding(MetricsEncodingEnum::snappy); @@ -781,6 +793,8 @@ void FreeMonProcessor::doAsyncMetricsComplete( // Disable free monitoring on validation errors _state->setState(StorageStateEnum::disabled); + _registrationStatus = FreeMonRegistrationStatus::kDisabled; + writeState(client); // If validation fails, we do not retry @@ -793,6 +807,7 @@ void FreeMonProcessor::doAsyncMetricsComplete( FreeMonStorage::deleteState(opCtxUnique.get()); _state->setState(StorageStateEnum::pending); + _registrationStatus = FreeMonRegistrationStatus::kDisabled; // Clear out the in-memory state _lastReadState = boost::none; @@ -833,9 +848,13 @@ void FreeMonProcessor::doAsyncMetricsComplete( _metricsRetry->setMin(Seconds(resp.getReportingInterval())); _metricsRetry->reset(); - // Enqueue next metrics upload - enqueue(FreeMonMessage::createWithDeadline(FreeMonMessageType::MetricsSend, - _metricsRetry->getNextDeadline(client))); + if (resp.getResendRegistration().is_initialized() && resp.getResendRegistration()) { + enqueue(FreeMonRegisterCommandMessage::createNow(_tags)); + } else { + // Enqueue next metrics upload + enqueue(FreeMonMessage::createWithDeadline(FreeMonMessageType::MetricsSend, + _metricsRetry->getNextDeadline(client))); + } } void FreeMonProcessor::doAsyncMetricsFail( @@ -952,6 +971,7 @@ void FreeMonProcessor::doNotifyOnDelete(Client* client) { // So we mark the internal state as disabled which stop registration and metrics send _state->setState(StorageStateEnum::pending); + _registrationStatus = FreeMonRegistrationStatus::kDisabled; // Clear out the in-memory state _lastReadState = boost::none; diff --git a/src/mongo/db/free_mon/free_mon_processor.h b/src/mongo/db/free_mon/free_mon_processor.h index cfaf1b504ad..f16a810f5b7 100644 --- a/src/mongo/db/free_mon/free_mon_processor.h +++ b/src/mongo/db/free_mon/free_mon_processor.h @@ -272,6 +272,27 @@ private: size_t _count; }; +/** + * In-memory registration status + * + * Ensures primaries and secondaries register separately + */ +enum class FreeMonRegistrationStatus { + /** + * Free monitoring is not enabled - default state. + */ + kDisabled, + + /** + * Registration in progress. + */ + kPending, + + /** + * Free Monitoring is enabled. + */ + kEnabled, +}; /** * Process in an Agent in a Agent/Message Passing model. @@ -479,6 +500,9 @@ private: // Pending update to disk boost::synchronized_value<FreeMonStorageState> _state; + // In-memory registration status + FreeMonRegistrationStatus _registrationStatus{FreeMonRegistrationStatus::kDisabled}; + // Countdown launch to support manual cranking FreeMonCountdownLatch _countdown; diff --git a/src/mongo/db/free_mon/free_mon_protocol.idl b/src/mongo/db/free_mon/free_mon_protocol.idl index b08e0638a0f..30fd9081ad3 100644 --- a/src/mongo/db/free_mon/free_mon_protocol.idl +++ b/src/mongo/db/free_mon/free_mon_protocol.idl @@ -95,7 +95,10 @@ structs: description: "Metrics Blob" type: bindata_generic - + # History + # ------- + # Version 2 - added resendRegistration bool + # FreeMonMetricsResponse: description: "Metrics Response from Cloud Server" fields: @@ -127,3 +130,7 @@ structs: description: "Message to display to user to remind them about service" type: string optional: true + resendRegistration: + description: "If true, resend registration to server" + type: bool + optional: true |