diff --git a/source/load-balancers/load-balancers.md b/source/load-balancers/load-balancers.md index c5c88de4cd..79ca900a94 100644 --- a/source/load-balancers/load-balancers.md +++ b/source/load-balancers/load-balancers.md @@ -81,8 +81,9 @@ Although there is no monitoring connection in load balanced mode, drivers MUST e - `TopologyDescriptionChangedEvent`. The `newDescription` MUST have `TopologyType` `LoadBalanced` and one server with `ServerType` `LoadBalancer`. -Drivers MUST also emit a `ServerClosedEvent` and `TopologyClosedEvent` when the topology is closed and MUST NOT emit any -other events when operating in this mode. +Drivers MUST also emit a `ServerClosedEvent` followed by a `TopologyDescriptionChangedEvent` that transitions the +`Topology` to the `UNKNOWN` state and a `TopologyClosedEvent` when the topology is closed and MUST NOT emit any other +events when operating in this mode. #### Log Messages @@ -328,6 +329,7 @@ only load balancers that support the PROXY protocol would be supported. ## Changelog +- 2024-04-25: Clarify that `TopologyDescriptionChangedEvent` must be emitted on topology close - 2024-03-06: Migrated from reStructuredText to Markdown. - 2022-10-05: Remove spec front matter and reformat changelog. - 2022-01-18: Clarify that `OP_MSG` must be used in load balanced mode. diff --git a/source/server-discovery-and-monitoring/server-discovery-and-monitoring-logging-and-monitoring.rst b/source/server-discovery-and-monitoring/server-discovery-and-monitoring-logging-and-monitoring.rst index 305008c878..36cf12f9d4 100644 --- a/source/server-discovery-and-monitoring/server-discovery-and-monitoring-logging-and-monitoring.rst +++ b/source/server-discovery-and-monitoring/server-discovery-and-monitoring-logging-and-monitoring.rst @@ -117,6 +117,12 @@ Initial Topology Description The first ``TopologyDescriptionChangedEvent`` to be emitted from a monitored Topology MUST set its ``previousDescription`` property to be a ``TopologyDescription`` object in the "unknown" state. +Closing Topology Description +---------------------------- + +When a ``Topology`` object or equivalent is being shut-down or closed, the driver MUST change the +``TopologyDescription`` to an "unknown" state. + ---------- Events API ---------- @@ -706,6 +712,7 @@ Changelog :2024-03-29: Updated to clarify expected initial value of TopologyDescriptionChangedEvent's previousDescription field +:2024-01-17: Updated to require that ``TopologyDescriptionChangedEvent`` should be emitted before just ``TopologyClosedEvent`` is emitted :2024-01-04: Updated to clarify when ServerHeartbeatStartedEvent should be emitted :2023-03-31: Renamed to include "logging" in the title. Reorganized contents and made consistent with CLAM spec, and added requirements for SDAM log messages. diff --git a/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst b/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst index e8c1810e18..2594b090a7 100644 --- a/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst +++ b/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst @@ -533,6 +533,15 @@ Single-threaded clients do no I/O in the constructor. They MUST `scan`_ the servers on demand, when the first operation is attempted. +Client closing +'''''''''''''' + +When a client is closing, before it emits the ``TopologyClosedEvent`` as per the +`Events API `_, +it SHOULD `remove`_ all servers from its ``TopologyDescription`` and set its +``TopologyType`` to ``Unknown``, emitting the corresponding +``TopologyDescriptionChangedEvent``. + Monitoring '''''''''' @@ -2543,6 +2552,7 @@ Changelog :2022-09-30: Update ``updateRSFromPrimary`` to include logic before and after 6.0 servers :2022-10-05: Remove spec front matter, move footnote, and reformat changelog. :2022-11-17: Add minimum RTT tracking and remove 90th percentile RTT. +:2024-01-17: Add section on expected client close behaviour ---- diff --git a/source/server-discovery-and-monitoring/tests/unified/loadbalanced-emit-topology-changed-before-close.json b/source/server-discovery-and-monitoring/tests/unified/loadbalanced-emit-topology-changed-before-close.json new file mode 100644 index 0000000000..30c0657630 --- /dev/null +++ b/source/server-discovery-and-monitoring/tests/unified/loadbalanced-emit-topology-changed-before-close.json @@ -0,0 +1,88 @@ +{ + "description": "loadbalanced-emit-topology-description-changed-before-close", + "schemaVersion": "1.20", + "runOnRequirements": [ + { + "topologies": [ + "load-balanced" + ], + "minServerVersion": "4.4" + } + ], + "tests": [ + { + "description": "Topology lifecycle", + "operations": [ + { + "name": "createEntities", + "object": "testRunner", + "arguments": { + "entities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "topologyDescriptionChangedEvent", + "topologyOpeningEvent", + "topologyClosedEvent" + ] + } + } + ] + } + }, + { + "name": "waitForEvent", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "topologyDescriptionChangedEvent": {} + }, + "count": 2 + } + }, + { + "name": "close", + "object": "client" + } + ], + "expectEvents": [ + { + "client": "client", + "eventType": "sdam", + "events": [ + { + "topologyOpeningEvent": {} + }, + { + "topologyDescriptionChangedEvent": { + "previousDescription": { + "type": "Unknown" + }, + "newDescription": {} + } + }, + { + "topologyDescriptionChangedEvent": { + "newDescription": { + "type": "LoadBalanced" + } + } + }, + { + "topologyDescriptionChangedEvent": { + "newDescription": { + "type": "Unknown" + } + } + }, + { + "topologyClosedEvent": {} + } + ] + } + ] + } + ] +} diff --git a/source/server-discovery-and-monitoring/tests/unified/loadbalanced-emit-topology-changed-before-close.yml b/source/server-discovery-and-monitoring/tests/unified/loadbalanced-emit-topology-changed-before-close.yml new file mode 100644 index 0000000000..c919a8cf8b --- /dev/null +++ b/source/server-discovery-and-monitoring/tests/unified/loadbalanced-emit-topology-changed-before-close.yml @@ -0,0 +1,49 @@ +description: "loadbalanced-emit-topology-description-changed-before-close" + +schemaVersion: "1.20" + +runOnRequirements: + - topologies: + - load-balanced + minServerVersion: "4.4" # awaitable hello + +tests: + - description: "Topology lifecycle" + operations: + - name: createEntities + object: testRunner + arguments: + entities: + - client: + id: &client client + observeEvents: + - topologyDescriptionChangedEvent + - topologyOpeningEvent + - topologyClosedEvent + # ensure the topology has been fully discovered before closing the client. + # expected events are initial server discovery and server connect event. + - name: waitForEvent + object: testRunner + arguments: + client: *client + event: + topologyDescriptionChangedEvent: {} + count: 2 + - name: close + object: *client + expectEvents: + - client: *client + eventType: sdam + events: + - topologyOpeningEvent: {} + - topologyDescriptionChangedEvent: # unknown -> unknown w disconnected server + previousDescription: + type: "Unknown" + newDescription: {} + - topologyDescriptionChangedEvent: # unknown w disconnected server -> loadBalanced + newDescription: + type: "LoadBalanced" + - topologyDescriptionChangedEvent: # loadbalanced -> unknown + newDescription: + type: "Unknown" + - topologyClosedEvent: {} diff --git a/source/server-discovery-and-monitoring/tests/unified/logging-loadbalanced.json b/source/server-discovery-and-monitoring/tests/unified/logging-loadbalanced.json index 45440d2557..0ad3b0ceaa 100644 --- a/source/server-discovery-and-monitoring/tests/unified/logging-loadbalanced.json +++ b/source/server-discovery-and-monitoring/tests/unified/logging-loadbalanced.json @@ -132,6 +132,22 @@ } } }, + { + "level": "debug", + "component": "topology", + "data": { + "message": "Topology description changed", + "topologyId": { + "$$exists": true + }, + "previousDescription": { + "$$exists": true + }, + "newDescription": { + "$$exists": true + } + } + }, { "level": "debug", "component": "topology", diff --git a/source/server-discovery-and-monitoring/tests/unified/logging-loadbalanced.yml b/source/server-discovery-and-monitoring/tests/unified/logging-loadbalanced.yml index 3f6058270f..432ec354ed 100644 --- a/source/server-discovery-and-monitoring/tests/unified/logging-loadbalanced.yml +++ b/source/server-discovery-and-monitoring/tests/unified/logging-loadbalanced.yml @@ -67,8 +67,15 @@ tests: topologyId: { $$exists: true } serverHost: { $$type: string } serverPort: { $$type: [int, long] } + - level: debug + component: topology + data: + message: "Topology description changed" + topologyId: { $$exists: true } + previousDescription: { $$exists: true } # loadBalanced topology + newDescription: { $$exists: true } # unknown topology - level: debug component: topology data: message: "Stopped topology monitoring" - topologyId: { $$exists: true } \ No newline at end of file + topologyId: { $$exists: true } diff --git a/source/server-discovery-and-monitoring/tests/unified/replicaset-emit-topology-changed-before-close.json b/source/server-discovery-and-monitoring/tests/unified/replicaset-emit-topology-changed-before-close.json new file mode 100644 index 0000000000..066a4ffee5 --- /dev/null +++ b/source/server-discovery-and-monitoring/tests/unified/replicaset-emit-topology-changed-before-close.json @@ -0,0 +1,89 @@ +{ + "description": "replicaset-emit-topology-description-changed-before-close", + "schemaVersion": "1.20", + "runOnRequirements": [ + { + "topologies": [ + "replicaset" + ], + "minServerVersion": "4.4" + } + ], + "tests": [ + { + "description": "Topology lifecycle", + "operations": [ + { + "name": "createEntities", + "object": "testRunner", + "arguments": { + "entities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "topologyDescriptionChangedEvent", + "topologyOpeningEvent", + "topologyClosedEvent" + ] + } + } + ] + } + }, + { + "name": "waitForEvent", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "topologyDescriptionChangedEvent": {} + }, + "count": 4 + } + }, + { + "name": "close", + "object": "client" + } + ], + "expectEvents": [ + { + "client": "client", + "eventType": "sdam", + "ignoreExtraEvents": false, + "events": [ + { + "topologyOpeningEvent": {} + }, + { + "topologyDescriptionChangedEvent": {} + }, + { + "topologyDescriptionChangedEvent": {} + }, + { + "topologyDescriptionChangedEvent": {} + }, + { + "topologyDescriptionChangedEvent": {} + }, + { + "topologyDescriptionChangedEvent": { + "previousDescription": { + "type": "ReplicaSetWithPrimary" + }, + "newDescription": { + "type": "Unknown" + } + } + }, + { + "topologyClosedEvent": {} + } + ] + } + ] + } + ] +} diff --git a/source/server-discovery-and-monitoring/tests/unified/replicaset-emit-topology-changed-before-close.yml b/source/server-discovery-and-monitoring/tests/unified/replicaset-emit-topology-changed-before-close.yml new file mode 100644 index 0000000000..d0a1158ea9 --- /dev/null +++ b/source/server-discovery-and-monitoring/tests/unified/replicaset-emit-topology-changed-before-close.yml @@ -0,0 +1,49 @@ +description: "replicaset-emit-topology-description-changed-before-close" + +schemaVersion: "1.20" + +runOnRequirements: + - topologies: + - replicaset + minServerVersion: "4.4" # awaitable hello + +tests: + - description: "Topology lifecycle" + operations: + - name: createEntities + object: testRunner + arguments: + entities: + - client: + id: &client client + observeEvents: + - topologyDescriptionChangedEvent + - topologyOpeningEvent + - topologyClosedEvent + # ensure the topology has been fully discovered before closing the client. + # expected events are initial server discovery and 3 server connect events. + - name: waitForEvent + object: testRunner + arguments: + client: *client + event: + topologyDescriptionChangedEvent: {} + count: 4 + - name: close + object: *client + expectEvents: + - client: *client + eventType: sdam + ignoreExtraEvents: false + events: + - topologyOpeningEvent: {} + - topologyDescriptionChangedEvent: {} # unknown -> replset no primary + - topologyDescriptionChangedEvent: {} # server connected + - topologyDescriptionChangedEvent: {} # server connected + - topologyDescriptionChangedEvent: {} # server connected + - topologyDescriptionChangedEvent: # replicaset -> unknown + previousDescription: + type: "ReplicaSetWithPrimary" + newDescription: + type: "Unknown" + - topologyClosedEvent: {} diff --git a/source/server-discovery-and-monitoring/tests/unified/sharded-emit-topology-changed-before-close.json b/source/server-discovery-and-monitoring/tests/unified/sharded-emit-topology-changed-before-close.json new file mode 100644 index 0000000000..98fb585531 --- /dev/null +++ b/source/server-discovery-and-monitoring/tests/unified/sharded-emit-topology-changed-before-close.json @@ -0,0 +1,108 @@ +{ + "description": "sharded-emit-topology-description-changed-before-close", + "schemaVersion": "1.20", + "runOnRequirements": [ + { + "topologies": [ + "sharded" + ], + "minServerVersion": "4.4" + } + ], + "tests": [ + { + "description": "Topology lifecycle", + "operations": [ + { + "name": "createEntities", + "object": "testRunner", + "arguments": { + "entities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "topologyDescriptionChangedEvent", + "topologyOpeningEvent", + "topologyClosedEvent" + ], + "useMultipleMongoses": true + } + } + ] + } + }, + { + "name": "waitForEvent", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "topologyDescriptionChangedEvent": {} + }, + "count": 3 + } + }, + { + "name": "close", + "object": "client" + } + ], + "expectEvents": [ + { + "client": "client", + "eventType": "sdam", + "ignoreExtraEvents": false, + "events": [ + { + "topologyOpeningEvent": {} + }, + { + "topologyDescriptionChangedEvent": { + "previousDescription": { + "type": "Unknown" + }, + "newDescription": { + "type": "Unknown" + } + } + }, + { + "topologyDescriptionChangedEvent": { + "previousDescription": { + "type": "Unknown" + }, + "newDescription": { + "type": "Sharded" + } + } + }, + { + "topologyDescriptionChangedEvent": { + "previousDescription": { + "type": "Sharded" + }, + "newDescription": { + "type": "Sharded" + } + } + }, + { + "topologyDescriptionChangedEvent": { + "previousDescription": { + "type": "Sharded" + }, + "newDescription": { + "type": "Unknown" + } + } + }, + { + "topologyClosedEvent": {} + } + ] + } + ] + } + ] +} diff --git a/source/server-discovery-and-monitoring/tests/unified/sharded-emit-topology-changed-before-close.yml b/source/server-discovery-and-monitoring/tests/unified/sharded-emit-topology-changed-before-close.yml new file mode 100644 index 0000000000..cb6cc5ad4d --- /dev/null +++ b/source/server-discovery-and-monitoring/tests/unified/sharded-emit-topology-changed-before-close.yml @@ -0,0 +1,62 @@ +description: "sharded-emit-topology-description-changed-before-close" + +schemaVersion: "1.20" + +runOnRequirements: + - topologies: + - sharded + minServerVersion: "4.4" # awaitable hello + +tests: + - description: "Topology lifecycle" + operations: + - name: createEntities + object: testRunner + arguments: + entities: + - client: + id: &client client + observeEvents: + - topologyDescriptionChangedEvent + - topologyOpeningEvent + - topologyClosedEvent + useMultipleMongoses: true + # ensure the topology has been fully discovered before closing the client. + # expected events are initial cluster type change from unknown to sharded and connect events + # for each of 2 servers + - name: waitForEvent + object: testRunner + arguments: + client: *client + event: + topologyDescriptionChangedEvent: {} + count: 3 + - name: close + object: *client + expectEvents: + - client: *client + eventType: sdam + ignoreExtraEvents: false + events: + - topologyOpeningEvent: {} + - topologyDescriptionChangedEvent: # unknown -> unknown w disconnected server + previousDescription: + type: "Unknown" + newDescription: + type: "Unknown" + - topologyDescriptionChangedEvent: # server connected + previousDescription: + type: "Unknown" + newDescription: + type: "Sharded" + - topologyDescriptionChangedEvent: # server connected + previousDescription: + type: "Sharded" + newDescription: + type: "Sharded" + - topologyDescriptionChangedEvent: # sharded -> unknown + previousDescription: + type: "Sharded" + newDescription: + type: "Unknown" + - topologyClosedEvent: {} diff --git a/source/server-discovery-and-monitoring/tests/unified/standalone-emit-topology-changed-before-close.json b/source/server-discovery-and-monitoring/tests/unified/standalone-emit-topology-changed-before-close.json new file mode 100644 index 0000000000..27b5444d54 --- /dev/null +++ b/source/server-discovery-and-monitoring/tests/unified/standalone-emit-topology-changed-before-close.json @@ -0,0 +1,97 @@ +{ + "description": "standalone-emit-topology-description-changed-before-close", + "schemaVersion": "1.20", + "runOnRequirements": [ + { + "topologies": [ + "single" + ], + "minServerVersion": "4.4" + } + ], + "tests": [ + { + "description": "Topology lifecycle", + "operations": [ + { + "name": "createEntities", + "object": "testRunner", + "arguments": { + "entities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "topologyDescriptionChangedEvent", + "topologyOpeningEvent", + "topologyClosedEvent" + ] + } + } + ] + } + }, + { + "name": "waitForEvent", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "topologyDescriptionChangedEvent": {} + }, + "count": 2 + } + }, + { + "name": "close", + "object": "client" + } + ], + "expectEvents": [ + { + "client": "client", + "eventType": "sdam", + "ignoreExtraEvents": false, + "events": [ + { + "topologyOpeningEvent": {} + }, + { + "topologyDescriptionChangedEvent": { + "previousDescription": { + "type": "Unknown" + }, + "newDescription": { + "type": "Unknown" + } + } + }, + { + "topologyDescriptionChangedEvent": { + "previousDescription": { + "type": "Unknown" + }, + "newDescription": { + "type": "Single" + } + } + }, + { + "topologyDescriptionChangedEvent": { + "previousDescription": { + "type": "Single" + }, + "newDescription": { + "type": "Unknown" + } + } + }, + { + "topologyClosedEvent": {} + } + ] + } + ] + } + ] +} diff --git a/source/server-discovery-and-monitoring/tests/unified/standalone-emit-topology-changed-before-close.yml b/source/server-discovery-and-monitoring/tests/unified/standalone-emit-topology-changed-before-close.yml new file mode 100644 index 0000000000..20fa380bd5 --- /dev/null +++ b/source/server-discovery-and-monitoring/tests/unified/standalone-emit-topology-changed-before-close.yml @@ -0,0 +1,55 @@ +description: "standalone-emit-topology-description-changed-before-close" + +schemaVersion: "1.20" + +runOnRequirements: + - topologies: + - single + minServerVersion: "4.4" # awaitable hello + +tests: + - description: "Topology lifecycle" + operations: + - name: createEntities + object: testRunner + arguments: + entities: + - client: + id: &client client + observeEvents: + - topologyDescriptionChangedEvent + - topologyOpeningEvent + - topologyClosedEvent + # ensure the topology has been fully discovered before closing the client. + # expected events are initial server discovery and server connect event. + - name: waitForEvent + object: testRunner + arguments: + client: *client + event: + topologyDescriptionChangedEvent: {} + count: 2 + - name: close + object: *client + expectEvents: + - client: *client + eventType: sdam + ignoreExtraEvents: false + events: + - topologyOpeningEvent: {} + - topologyDescriptionChangedEvent: # unknown -> unknown w disconnected server + previousDescription: + type: "Unknown" + newDescription: + type: "Unknown" + - topologyDescriptionChangedEvent: # unknown w disconnected server -> standalone + previousDescription: + type: "Unknown" + newDescription: + type: "Single" + - topologyDescriptionChangedEvent: # standalone -> unknown + previousDescription: + type: "Single" + newDescription: + type: "Unknown" + - topologyClosedEvent: {}