@omen.foundation/node-microservice-runtime 0.1.49 → 0.1.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -82,6 +82,7 @@ let globalCollectorProcess = null;
82
82
  let globalCollectorStartError = null;
83
83
  let globalCollectorExitCode = null;
84
84
  let globalCollectorStderr = [];
85
+ let globalCollectorStartupPromise = null;
85
86
  let globalCollectorInitError = null;
86
87
  function calculateSignature(pid, secret, uriPathAndQuery, body = null, version = '1') {
87
88
  let dataToSign = `${secret}${pid}${version}${uriPathAndQuery}`;
@@ -640,6 +641,18 @@ async function discoverOrStartCollector(logger, standardOtelEnabled, env) {
640
641
  if (!standardOtelEnabled) {
641
642
  return null;
642
643
  }
644
+ if (globalCollectorStartupPromise) {
645
+ logger.info('[Collector] Collector startup already in progress, waiting for existing startup to complete...');
646
+ try {
647
+ const result = await globalCollectorStartupPromise;
648
+ globalCollectorStartupPromise = null;
649
+ return result;
650
+ }
651
+ catch (error) {
652
+ logger.error(`[Collector] Existing startup promise failed: ${error instanceof Error ? error.message : String(error)}`);
653
+ globalCollectorStartupPromise = null;
654
+ }
655
+ }
643
656
  let existingEndpoint;
644
657
  if (globalCollectorProcess) {
645
658
  const processAlive = globalCollectorProcess.exitCode === null &&
@@ -664,59 +677,66 @@ async function discoverOrStartCollector(logger, standardOtelEnabled, env) {
664
677
  return `http://${status.otlpEndpoint}`;
665
678
  }
666
679
  }
667
- try {
668
- globalCollectorInitError = null;
669
- let endpoint;
670
- if (existingEndpoint) {
671
- endpoint = existingEndpoint;
672
- logger.info(`[Collector] Waiting for existing collector to become ready at ${endpoint}...`);
673
- }
674
- else {
675
- logger.info('[Collector] Starting OpenTelemetry collector...');
676
- const startResult = await startCollector(logger, undefined, env);
677
- endpoint = startResult.endpoint;
678
- await new Promise(resolve => setTimeout(resolve, 200));
679
- if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {
680
- const errorMsg = `Collector process exited immediately with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;
681
- globalCollectorInitError = errorMsg;
682
- logger.error(`[Collector] ${errorMsg}`);
683
- return null;
680
+ const startupPromise = (async () => {
681
+ try {
682
+ globalCollectorInitError = null;
683
+ let endpoint;
684
+ if (existingEndpoint) {
685
+ endpoint = existingEndpoint;
686
+ logger.info(`[Collector] Waiting for existing collector to become ready at ${endpoint}...`);
687
+ }
688
+ else {
689
+ logger.info('[Collector] Starting OpenTelemetry collector...');
690
+ const startResult = await startCollector(logger, undefined, env);
691
+ endpoint = startResult.endpoint;
692
+ await new Promise(resolve => setTimeout(resolve, 200));
693
+ if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {
694
+ const errorMsg = `Collector process exited immediately with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;
695
+ globalCollectorInitError = errorMsg;
696
+ logger.error(`[Collector] ${errorMsg}`);
697
+ return null;
698
+ }
699
+ }
700
+ const maxWaitTime = 60000;
701
+ const checkInterval = 500;
702
+ const maxChecks = Math.floor(maxWaitTime / checkInterval);
703
+ logger.info('[Collector] Waiting for collector to become ready...');
704
+ for (let i = 0; i < maxChecks; i++) {
705
+ await new Promise(resolve => setTimeout(resolve, checkInterval));
706
+ if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {
707
+ const errorMsg = `Collector process exited during startup with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;
708
+ globalCollectorInitError = errorMsg;
709
+ logger.error(`[Collector] ${errorMsg}`);
710
+ return null;
711
+ }
712
+ const newStatus = await isCollectorRunning();
713
+ if (newStatus.isRunning && newStatus.isReady) {
714
+ logger.info(`[Collector] Collector is ready at ${newStatus.otlpEndpoint || endpoint}`);
715
+ return newStatus.otlpEndpoint ? `http://${newStatus.otlpEndpoint}` : endpoint;
716
+ }
717
+ if (i > 0 && i % 4 === 0) {
718
+ logger.info(`[Collector] Still waiting for collector to become ready... (${(i * checkInterval) / 1000}s elapsed)`);
719
+ }
684
720
  }
685
- }
686
- const maxWaitTime = 60000;
687
- const checkInterval = 500;
688
- const maxChecks = Math.floor(maxWaitTime / checkInterval);
689
- logger.info('[Collector] Waiting for collector to become ready...');
690
- for (let i = 0; i < maxChecks; i++) {
691
- await new Promise(resolve => setTimeout(resolve, checkInterval));
692
721
  if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {
693
- const errorMsg = `Collector process exited during startup with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;
722
+ const errorMsg = `Collector process exited with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;
694
723
  globalCollectorInitError = errorMsg;
695
724
  logger.error(`[Collector] ${errorMsg}`);
696
725
  return null;
697
726
  }
698
- const newStatus = await isCollectorRunning();
699
- if (newStatus.isRunning && newStatus.isReady) {
700
- logger.info(`[Collector] Collector is ready at ${newStatus.otlpEndpoint || endpoint}`);
701
- return newStatus.otlpEndpoint ? `http://${newStatus.otlpEndpoint}` : endpoint;
702
- }
703
- if (i > 0 && i % 4 === 0) {
704
- logger.info(`[Collector] Still waiting for collector to become ready... (${(i * checkInterval) / 1000}s elapsed)`);
705
- }
727
+ logger.error(`[Collector] Collector did not become ready within ${maxWaitTime / 1000} seconds`);
728
+ return null;
706
729
  }
707
- if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {
708
- const errorMsg = `Collector process exited with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;
730
+ catch (err) {
731
+ const errorMsg = err instanceof Error ? err.message : String(err);
709
732
  globalCollectorInitError = errorMsg;
710
- logger.error(`[Collector] ${errorMsg}`);
733
+ logger.error(`[Collector] Failed to start collector: ${errorMsg}`);
711
734
  return null;
712
735
  }
713
- logger.error(`[Collector] Collector did not become ready within ${maxWaitTime / 1000} seconds`);
714
- return null;
715
- }
716
- catch (err) {
717
- const errorMsg = err instanceof Error ? err.message : String(err);
718
- globalCollectorInitError = errorMsg;
719
- logger.error(`[Collector] Failed to start collector: ${errorMsg}`);
720
- return null;
721
- }
736
+ })();
737
+ globalCollectorStartupPromise = startupPromise;
738
+ startupPromise.finally(() => {
739
+ globalCollectorStartupPromise = null;
740
+ });
741
+ return await startupPromise;
722
742
  }
@@ -1 +1 @@
1
- {"version":3,"file":"collector-manager.d.ts","sourceRoot":"","sources":["../src/collector-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,YAAY,EAAE,MAAM,eAAe,CAAC;AAOpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAInC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAYpD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAqCD;;GAEG;AACH,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAqCD;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,qBAAqB,CAAC,CAwChC;AA0OD;;GAEG;AACH,wBAAgB,8BAA8B,IAAI;IAChD,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,aAAa,GAAG,KAAK,GAAG,SAAS,CAAC;CAC3C,CAoBA;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,eAAe,CAAC,CAyEnE;AA0BD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAYjG;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,iBAAiB,EACtB,SAAS,GAAE,MAAc,GACxB,MAAM,GAAG,IAAI,CA8Ef;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,EACrB,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgNtD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI;IAC3C,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CASA;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,OAAO,EAC5B,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmHxB"}
1
+ {"version":3,"file":"collector-manager.d.ts","sourceRoot":"","sources":["../src/collector-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,YAAY,EAAE,MAAM,eAAe,CAAC;AAOpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAInC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAYpD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAuCD;;GAEG;AACH,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAqCD;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,qBAAqB,CAAC,CAwChC;AA0OD;;GAEG;AACH,wBAAgB,8BAA8B,IAAI;IAChD,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,aAAa,GAAG,KAAK,GAAG,SAAS,CAAC;CAC3C,CAoBA;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,eAAe,CAAC,CAyEnE;AA0BD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAYjG;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,iBAAiB,EACtB,SAAS,GAAE,MAAc,GACxB,MAAM,GAAG,IAAI,CA8Ef;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,EACrB,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgNtD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI;IAC3C,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CASA;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,OAAO,EAC5B,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmJxB"}
@@ -41,6 +41,8 @@ let globalCollectorProcess = null;
41
41
  let globalCollectorStartError = null;
42
42
  let globalCollectorExitCode = null;
43
43
  let globalCollectorStderr = [];
44
+ // Track if collector startup is in progress to prevent duplicate starts
45
+ let globalCollectorStartupPromise = null;
44
46
  let globalCollectorInitError = null; // Tracks errors from discoverOrStartCollector
45
47
  /**
46
48
  * Calculates Beamable signature for signed requests
@@ -744,6 +746,24 @@ export async function discoverOrStartCollector(logger, standardOtelEnabled, env)
744
746
  if (!standardOtelEnabled) {
745
747
  return null;
746
748
  }
749
+ // CRITICAL: Check if collector startup is already in progress
750
+ // This prevents duplicate collector starts if this function is called multiple times
751
+ // (e.g., if setupCollectorBeforeLogging times out but the promise is still running)
752
+ if (globalCollectorStartupPromise) {
753
+ logger.info('[Collector] Collector startup already in progress, waiting for existing startup to complete...');
754
+ try {
755
+ const result = await globalCollectorStartupPromise;
756
+ // Clear the promise after it completes (success or failure)
757
+ globalCollectorStartupPromise = null;
758
+ return result;
759
+ }
760
+ catch (error) {
761
+ logger.error(`[Collector] Existing startup promise failed: ${error instanceof Error ? error.message : String(error)}`);
762
+ // Clear the promise so we can retry
763
+ globalCollectorStartupPromise = null;
764
+ // Fall through to start a new one
765
+ }
766
+ }
747
767
  // CRITICAL: Check if we already have a collector process starting/running
748
768
  // This prevents duplicate collector starts if this function is called multiple times
749
769
  let existingEndpoint;
@@ -776,72 +796,83 @@ export async function discoverOrStartCollector(logger, standardOtelEnabled, env)
776
796
  }
777
797
  }
778
798
  // Collector not running - start it (or wait for existing one to be ready)
779
- try {
780
- // Clear any previous init error
781
- globalCollectorInitError = null;
782
- let endpoint;
783
- if (existingEndpoint) {
784
- // Collector already starting, just wait for it to be ready
785
- endpoint = existingEndpoint;
786
- logger.info(`[Collector] Waiting for existing collector to become ready at ${endpoint}...`);
787
- }
788
- else {
789
- // Start a new collector
790
- logger.info('[Collector] Starting OpenTelemetry collector...');
791
- const startResult = await startCollector(logger, undefined, env);
792
- endpoint = startResult.endpoint;
793
- // Check if collector process exited immediately (crashed)
794
- // Wait a bit longer to see if it crashes right after starting
795
- await new Promise(resolve => setTimeout(resolve, 200));
796
- if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {
797
- const errorMsg = `Collector process exited immediately with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;
798
- globalCollectorInitError = errorMsg;
799
- logger.error(`[Collector] ${errorMsg}`);
800
- return null;
799
+ // Wrap the entire startup logic in a promise that we track globally
800
+ // This prevents duplicate starts if this function is called multiple times
801
+ const startupPromise = (async () => {
802
+ try {
803
+ // Clear any previous init error
804
+ globalCollectorInitError = null;
805
+ let endpoint;
806
+ if (existingEndpoint) {
807
+ // Collector already starting, just wait for it to be ready
808
+ endpoint = existingEndpoint;
809
+ logger.info(`[Collector] Waiting for existing collector to become ready at ${endpoint}...`);
801
810
  }
802
- }
803
- // CRITICAL: Wait for collector to be fully ready before returning
804
- // We'll wait up to 60 seconds, checking every 500ms
805
- // This ensures the collector is actually ready to receive logs before we continue
806
- const maxWaitTime = 60000; // 60 seconds
807
- const checkInterval = 500; // Check every 500ms
808
- const maxChecks = Math.floor(maxWaitTime / checkInterval);
809
- logger.info('[Collector] Waiting for collector to become ready...');
810
- for (let i = 0; i < maxChecks; i++) {
811
- await new Promise(resolve => setTimeout(resolve, checkInterval));
812
- // Check if process exited during wait
811
+ else {
812
+ // Start a new collector
813
+ logger.info('[Collector] Starting OpenTelemetry collector...');
814
+ const startResult = await startCollector(logger, undefined, env);
815
+ endpoint = startResult.endpoint;
816
+ // Check if collector process exited immediately (crashed)
817
+ // Wait a bit longer to see if it crashes right after starting
818
+ await new Promise(resolve => setTimeout(resolve, 200));
819
+ if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {
820
+ const errorMsg = `Collector process exited immediately with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;
821
+ globalCollectorInitError = errorMsg;
822
+ logger.error(`[Collector] ${errorMsg}`);
823
+ return null;
824
+ }
825
+ }
826
+ // CRITICAL: Wait for collector to be fully ready before returning
827
+ // We'll wait up to 60 seconds, checking every 500ms
828
+ // This ensures the collector is actually ready to receive logs before we continue
829
+ const maxWaitTime = 60000; // 60 seconds
830
+ const checkInterval = 500; // Check every 500ms
831
+ const maxChecks = Math.floor(maxWaitTime / checkInterval);
832
+ logger.info('[Collector] Waiting for collector to become ready...');
833
+ for (let i = 0; i < maxChecks; i++) {
834
+ await new Promise(resolve => setTimeout(resolve, checkInterval));
835
+ // Check if process exited during wait
836
+ if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {
837
+ const errorMsg = `Collector process exited during startup with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;
838
+ globalCollectorInitError = errorMsg;
839
+ logger.error(`[Collector] ${errorMsg}`);
840
+ return null;
841
+ }
842
+ const newStatus = await isCollectorRunning();
843
+ if (newStatus.isRunning && newStatus.isReady) {
844
+ logger.info(`[Collector] Collector is ready at ${newStatus.otlpEndpoint || endpoint}`);
845
+ return newStatus.otlpEndpoint ? `http://${newStatus.otlpEndpoint}` : endpoint;
846
+ }
847
+ // Log progress every 2 seconds
848
+ if (i > 0 && i % 4 === 0) {
849
+ logger.info(`[Collector] Still waiting for collector to become ready... (${(i * checkInterval) / 1000}s elapsed)`);
850
+ }
851
+ }
852
+ // Check one more time if process exited
813
853
  if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {
814
- const errorMsg = `Collector process exited during startup with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;
854
+ const errorMsg = `Collector process exited with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;
815
855
  globalCollectorInitError = errorMsg;
816
856
  logger.error(`[Collector] ${errorMsg}`);
817
857
  return null;
818
858
  }
819
- const newStatus = await isCollectorRunning();
820
- if (newStatus.isRunning && newStatus.isReady) {
821
- logger.info(`[Collector] Collector is ready at ${newStatus.otlpEndpoint || endpoint}`);
822
- return newStatus.otlpEndpoint ? `http://${newStatus.otlpEndpoint}` : endpoint;
823
- }
824
- // Log progress every 2 seconds
825
- if (i > 0 && i % 4 === 0) {
826
- logger.info(`[Collector] Still waiting for collector to become ready... (${(i * checkInterval) / 1000}s elapsed)`);
827
- }
859
+ // Collector did not become ready within timeout
860
+ logger.error(`[Collector] Collector did not become ready within ${maxWaitTime / 1000} seconds`);
861
+ return null;
828
862
  }
829
- // Check one more time if process exited
830
- if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {
831
- const errorMsg = `Collector process exited with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;
863
+ catch (err) {
864
+ const errorMsg = err instanceof Error ? err.message : String(err);
832
865
  globalCollectorInitError = errorMsg;
833
- logger.error(`[Collector] ${errorMsg}`);
866
+ logger.error(`[Collector] Failed to start collector: ${errorMsg}`);
834
867
  return null;
835
868
  }
836
- // Collector did not become ready within timeout
837
- logger.error(`[Collector] Collector did not become ready within ${maxWaitTime / 1000} seconds`);
838
- return null;
839
- }
840
- catch (err) {
841
- const errorMsg = err instanceof Error ? err.message : String(err);
842
- globalCollectorInitError = errorMsg;
843
- logger.error(`[Collector] Failed to start collector: ${errorMsg}`);
844
- return null;
845
- }
869
+ })();
870
+ // Store the promise globally so other calls to this function can wait for it
871
+ globalCollectorStartupPromise = startupPromise;
872
+ // Clear the promise when it completes (so we don't keep waiting on old promises)
873
+ startupPromise.finally(() => {
874
+ globalCollectorStartupPromise = null;
875
+ });
876
+ return await startupPromise;
846
877
  }
847
878
  //# sourceMappingURL=collector-manager.js.map