mongocryptd_manager.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.MongocryptdManager = void 0;
  4. const error_1 = require("../error");
  5. /**
  6. * @internal
  7. * An internal class that handles spawning a mongocryptd.
  8. */
  9. class MongocryptdManager {
  10. constructor(extraOptions = {}) {
  11. this.uri =
  12. typeof extraOptions.mongocryptdURI === 'string' && extraOptions.mongocryptdURI.length > 0
  13. ? extraOptions.mongocryptdURI
  14. : MongocryptdManager.DEFAULT_MONGOCRYPTD_URI;
  15. this.bypassSpawn = !!extraOptions.mongocryptdBypassSpawn;
  16. this.spawnPath = extraOptions.mongocryptdSpawnPath || '';
  17. this.spawnArgs = [];
  18. if (Array.isArray(extraOptions.mongocryptdSpawnArgs)) {
  19. this.spawnArgs = this.spawnArgs.concat(extraOptions.mongocryptdSpawnArgs);
  20. }
  21. if (this.spawnArgs
  22. .filter(arg => typeof arg === 'string')
  23. .every(arg => arg.indexOf('--idleShutdownTimeoutSecs') < 0)) {
  24. this.spawnArgs.push('--idleShutdownTimeoutSecs', '60');
  25. }
  26. }
  27. /**
  28. * Will check to see if a mongocryptd is up. If it is not up, it will attempt
  29. * to spawn a mongocryptd in a detached process, and then wait for it to be up.
  30. */
  31. async spawn() {
  32. const cmdName = this.spawnPath || 'mongocryptd';
  33. // eslint-disable-next-line @typescript-eslint/no-var-requires
  34. const { spawn } = require('child_process');
  35. // Spawned with stdio: ignore and detached: true
  36. // to ensure child can outlive parent.
  37. this._child = spawn(cmdName, this.spawnArgs, {
  38. stdio: 'ignore',
  39. detached: true
  40. });
  41. this._child.on('error', () => {
  42. // From the FLE spec:
  43. // "The stdout and stderr of the spawned process MUST not be exposed in the driver
  44. // (e.g. redirect to /dev/null). Users can pass the argument --logpath to
  45. // extraOptions.mongocryptdSpawnArgs if they need to inspect mongocryptd logs.
  46. // If spawning is necessary, the driver MUST spawn mongocryptd whenever server
  47. // selection on the MongoClient to mongocryptd fails. If the MongoClient fails to
  48. // connect after spawning, the server selection error is propagated to the user."
  49. // The AutoEncrypter and MongoCryptdManager should work together to spawn
  50. // mongocryptd whenever necessary. Additionally, the `mongocryptd` intentionally
  51. // shuts down after 60s and gets respawned when necessary. We rely on server
  52. // selection timeouts when connecting to the `mongocryptd` to inform users that something
  53. // has been configured incorrectly. For those reasons, we suppress stderr from
  54. // the `mongocryptd` process and immediately unref the process.
  55. });
  56. // unref child to remove handle from event loop
  57. this._child.unref();
  58. }
  59. /**
  60. * @returns the result of `fn` or rejects with an error.
  61. */
  62. async withRespawn(fn) {
  63. try {
  64. const result = await fn();
  65. return result;
  66. }
  67. catch (err) {
  68. // If we are not bypassing spawning, then we should retry once on a MongoTimeoutError (server selection error)
  69. const shouldSpawn = err instanceof error_1.MongoNetworkTimeoutError && !this.bypassSpawn;
  70. if (!shouldSpawn) {
  71. throw err;
  72. }
  73. }
  74. await this.spawn();
  75. const result = await fn();
  76. return result;
  77. }
  78. }
  79. MongocryptdManager.DEFAULT_MONGOCRYPTD_URI = 'mongodb://localhost:27020';
  80. exports.MongocryptdManager = MongocryptdManager;
  81. //# sourceMappingURL=mongocryptd_manager.js.map