mongocryptd_manager.js 3.9 KB

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