Uploaded image for project: 'C++ Driver'
  1. C++ Driver
  2. CXX-2381

Improve generic server errors returned to the client

    • Type: Icon: Improvement Improvement
    • Resolution: Won't Do
    • Priority: Icon: Unknown Unknown
    • None
    • Affects Version/s: None
    • Component/s: None

      This request is specifically for server-side connection limits being reached and not communicated back to the client application, however other server-side failures could be better reported to clients.

      For example, after adapting the connection pooling example as follows:

      // file: test.cpp
      // build: c++ --std=c++11 test.cpp -o test $(pkg-config --cflags --libs libmongocxx)  -lpthread
      #include <iostream>
      #include <ostream>
      #include <sstream>
      #include <thread>
      #include <vector>
      
      #include <bsoncxx/builder/basic/document.hpp>
      #include <bsoncxx/builder/basic/kvp.hpp>
      #include <bsoncxx/json.hpp>
      #include <bsoncxx/types.hpp>
      #include <mongocxx/client.hpp>
      #include <mongocxx/instance.hpp>
      #include <mongocxx/pool.hpp>
      #include <mongocxx/uri.hpp>
      
      using bsoncxx::builder::basic::kvp;
      
      int main() {
          // The mongocxx::instance constructor and destructor initialize and shut down the driver,
          // respectively. Therefore, a mongocxx::instance must be created before using the driver and
          // must remain alive for as long as the driver is in use.
          mongocxx::instance inst{};
          mongocxx::uri uri{"mongodb://localhost:27017/?minPoolSize=5&maxPoolSize=5"};
      
          mongocxx::pool pool{uri};
      
          std::vector<std::string> collection_names = {"foo", "bar", "baz"};
          std::vector<std::thread> threads{};
      
          for (auto i : {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) {
              auto run = [&](std::int64_t j) {
                  // Each client and collection can only be used in a single thread.
                  auto client = pool.acquire();
                  auto coll = (*client)["test"][collection_names[static_cast<std::size_t>(j)]];
                  coll.delete_many({});
      
                  bsoncxx::types::b_int64 index = {j};
                  coll.insert_one(bsoncxx::builder::basic::make_document(kvp("x", index)));
      
                  if (auto doc =
                          (*client)["test"][collection_names[static_cast<std::size_t>(j)]].find_one({})) {
                      // In order to ensure that the newline is printed immediately after the document,
                      // they need to be streamed to std::cout as a single string.
                      std::stringstream ss;
                      ss << bsoncxx::to_json(*doc) << std::endl;
      
                      std::cout << ss.str();
                  }
      
                  // The client goes out of scope at the end of the lambda and is returned to the pool.
              };
      
              std::thread runner{run, i};
      
              threads.push_back(std::move(runner));
          }
      
          for (auto&& runner : threads) {
              runner.join();
          }
      }
      

      And starting up a mongod with a hard limit of 5 simultaneous connections :

      m 4.4.9-ent
      rm -rf data && mkdir data 
      mongod --dbpath data --maxConns 5
      

      The application will fail with:

      terminate called after throwing an instance of 'mongocxx::v_noabi::bulk_write_exception'
        what():  Failed to send "isMaster" command with database "admin": socket error or timeout: generic server error
      Aborted (core dumped)
      

      The error message is not obviously actionable, though the mongod log in this case contains details that identify the cause of the failure:

      {"t":{"$date":"2021-10-05T10:59:55.937-04:00"},"s":"I","c":"NETWORK","id":51800,"ctx":"conn24","msg":"client metadata","attr":{"remote":"127.0.0.1:36876","client":"conn24","doc":{"driver":{"name":"mongoc / mongocxx","version":"1.17.4 / 3.6.2"},"os":{"type":"Linux","name":"Linux Mint","version":"20.2","architecture":"x86_64"},"platform":"(null)cfg=0x02a15ea0e9 posix=200809 stdc=201710 CC=GCC 9.3.0 CFLAGS=\"\" LDFLAGS=\"\""}}}

      {"t":{"$date":"2021-10-05T10:59:55.937-04:00"},"s":"I","c":"NETWORK","id":22942,"ctx":"listener","msg":"Connection refused because there are too many open connections","attr":{"connectionCount":6}}

            Assignee:
            roberto.sanchez@mongodb.com Roberto Sanchez
            Reporter:
            alex.bevilacqua@mongodb.com Alex Bevilacqua
            Votes:
            2 Vote for this issue
            Watchers:
            7 Start watching this issue

              Created:
              Updated:
              Resolved: