@agentunion/fastaun 0.5.10 → 0.5.11

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.
@@ -56,6 +56,9 @@ export declare class RPCTransport {
56
56
  private _actorTail;
57
57
  private _actorBusy;
58
58
  private _worker;
59
+ private _workerReady;
60
+ private _workerReadyTimer;
61
+ private _workerDisabled;
59
62
  private _workerPending;
60
63
  private _workerSeq;
61
64
  private _workerConnected;
@@ -72,6 +75,7 @@ export declare class RPCTransport {
72
75
  dnsNet?: import('./net.js').DnsResilientNet | null;
73
76
  });
74
77
  private _startNetworkWorker;
78
+ private _disableNetworkWorker;
75
79
  private _ensureNetworkWorker;
76
80
  private _dnsFallbackSnapshot;
77
81
  private _handleWorkerEvent;
package/dist/transport.js CHANGED
@@ -15,6 +15,8 @@ import { isJsonObject } from './types.js';
15
15
  const MAX_WS_PAYLOAD_SIZE = 1_000_000;
16
16
  const MAX_RPC_INFLIGHT = 16;
17
17
  const MAX_BACKGROUND_RPC_INFLIGHT = 8;
18
+ const WORKER_START_TIMEOUT_MS = 2_000;
19
+ const SHORT_RPC_WORKER_START_TIMEOUT_MS = 2_000;
18
20
  const _noopLogger = {
19
21
  error: () => { },
20
22
  warn: () => { },
@@ -402,6 +404,9 @@ export function shortRpcViaNetworkActor(url, method, params) {
402
404
  }
403
405
  const id = `short-rpc-${crypto.randomUUID()}`;
404
406
  let worker = null;
407
+ let workerReady = false;
408
+ let workerReadyTimer = null;
409
+ let localController = null;
405
410
  let settled = false;
406
411
  let resolveResult;
407
412
  let rejectResult;
@@ -410,6 +415,10 @@ export function shortRpcViaNetworkActor(url, method, params) {
410
415
  rejectResult = reject;
411
416
  });
412
417
  const cleanup = () => {
418
+ if (workerReadyTimer !== null) {
419
+ clearTimeout(workerReadyTimer);
420
+ workerReadyTimer = null;
421
+ }
413
422
  const current = worker;
414
423
  worker = null;
415
424
  if (!current)
@@ -431,12 +440,31 @@ export function shortRpcViaNetworkActor(url, method, params) {
431
440
  cleanup();
432
441
  rejectResult(error);
433
442
  };
443
+ const fallbackToLocal = () => {
444
+ if (settled || localController)
445
+ return;
446
+ cleanup();
447
+ localController = new AbortController();
448
+ void executeShortRpcEnvelope(url, method, params, localController.signal).then(resolveOnce, rejectOnce);
449
+ };
434
450
  try {
435
451
  worker = new Worker(new URL(import.meta.url), {
436
452
  execArgv: process.execArgv.filter((arg) => !arg.startsWith('--input-type')),
437
453
  workerData: { aunShortRpcWorker: true, id, url, method, params },
438
454
  });
455
+ workerReadyTimer = setTimeout(() => {
456
+ if (!workerReady && !settled)
457
+ fallbackToLocal();
458
+ }, SHORT_RPC_WORKER_START_TIMEOUT_MS);
439
459
  worker.on('message', (message) => {
460
+ if (message.type === 'ready' && message.id === id) {
461
+ workerReady = true;
462
+ if (workerReadyTimer !== null) {
463
+ clearTimeout(workerReadyTimer);
464
+ workerReadyTimer = null;
465
+ }
466
+ return;
467
+ }
440
468
  if (message.type !== 'reply' || message.id !== id)
441
469
  return;
442
470
  if (message.ok && isJsonObject(message.result))
@@ -444,17 +472,29 @@ export function shortRpcViaNetworkActor(url, method, params) {
444
472
  else
445
473
  rejectOnce(deserializeWorkerError(message.error));
446
474
  });
447
- worker.on('error', (error) => rejectOnce(new AuthError(`short RPC worker error: ${error.message}`)));
475
+ worker.on('error', (error) => {
476
+ if (!workerReady)
477
+ fallbackToLocal();
478
+ else
479
+ rejectOnce(new AuthError(`short RPC worker error: ${error.message}`));
480
+ });
448
481
  worker.on('exit', (code) => {
449
- if (!settled)
482
+ if (settled)
483
+ return;
484
+ if (!workerReady)
485
+ fallbackToLocal();
486
+ else
450
487
  rejectOnce(new AuthError(`short RPC worker exited: ${code}`));
451
488
  });
452
489
  }
453
490
  catch (error) {
454
- rejectOnce(new AuthError(`short RPC worker unavailable: ${error instanceof Error ? error.message : String(error)}`));
491
+ fallbackToLocal();
455
492
  }
456
493
  return Object.assign(promise, {
457
- cancel: () => rejectOnce(new AuthError('short RPC cancelled')),
494
+ cancel: () => {
495
+ localController?.abort();
496
+ rejectOnce(new AuthError('short RPC cancelled'));
497
+ },
458
498
  });
459
499
  }
460
500
  /**
@@ -498,6 +538,9 @@ export class RPCTransport {
498
538
  _actorTail = Promise.resolve();
499
539
  _actorBusy = false;
500
540
  _worker = null;
541
+ _workerReady = false;
542
+ _workerReadyTimer = null;
543
+ _workerDisabled = false;
501
544
  _workerPending = new Map();
502
545
  _workerSeq = 0;
503
546
  _workerConnected = false;
@@ -538,6 +581,8 @@ export class RPCTransport {
538
581
  }
539
582
  }
540
583
  _startNetworkWorker(opts) {
584
+ if (this._workerDisabled)
585
+ return;
541
586
  try {
542
587
  const worker = new Worker(new URL(import.meta.url), {
543
588
  execArgv: process.execArgv.filter((arg) => !arg.startsWith('--input-type')),
@@ -548,9 +593,23 @@ export class RPCTransport {
548
593
  },
549
594
  });
550
595
  this._worker = worker;
596
+ this._workerReady = false;
597
+ this._workerReadyTimer = setTimeout(() => {
598
+ if (this._worker === worker && !this._workerReady) {
599
+ this._disableNetworkWorker(worker, new ConnectionError('transport worker startup timeout'));
600
+ }
601
+ }, WORKER_START_TIMEOUT_MS);
551
602
  worker.on('message', (message) => {
552
603
  if (this._worker !== worker)
553
604
  return;
605
+ if (message.type === 'ready') {
606
+ this._workerReady = true;
607
+ if (this._workerReadyTimer !== null) {
608
+ clearTimeout(this._workerReadyTimer);
609
+ this._workerReadyTimer = null;
610
+ }
611
+ return;
612
+ }
554
613
  if (message.type === 'event') {
555
614
  this._handleWorkerEvent(message);
556
615
  return;
@@ -588,55 +647,69 @@ export class RPCTransport {
588
647
  }
589
648
  });
590
649
  worker.on('error', (error) => {
591
- if (this._worker !== worker)
592
- return;
593
- this._worker = null;
594
- this._workerConnected = false;
595
- this._workerConnecting = false;
596
- this._workerGeneration = null;
597
- this._workerBufferedEvents = [];
598
- for (const pending of this._workerPending.values()) {
599
- if (pending.timer !== null)
600
- clearTimeout(pending.timer);
601
- pending.reject(error);
602
- }
603
- this._workerPending.clear();
604
- this._dispatcher.enqueue('connection.error', { error });
650
+ this._disableNetworkWorker(worker, error);
605
651
  });
606
652
  worker.on('exit', (code) => {
607
- if (this._worker !== worker)
608
- return;
609
- this._worker = null;
610
- this._workerConnected = false;
611
- this._workerConnecting = false;
612
- this._workerGeneration = null;
613
- this._workerBufferedEvents = [];
614
653
  const error = new ConnectionError(`transport worker exited: ${code}`);
615
- for (const pending of this._workerPending.values()) {
616
- if (pending.timer !== null)
617
- clearTimeout(pending.timer);
618
- pending.reject(error);
619
- }
620
- this._workerPending.clear();
621
- if (code !== 0)
622
- this._dispatcher.enqueue('connection.error', { error: new Error(`transport worker exited: ${code}`) });
654
+ this._disableNetworkWorker(worker, error);
623
655
  });
624
656
  }
625
657
  catch (error) {
626
658
  this._worker = null;
659
+ this._workerReady = false;
660
+ if (this._workerReadyTimer !== null) {
661
+ clearTimeout(this._workerReadyTimer);
662
+ this._workerReadyTimer = null;
663
+ }
664
+ this._workerDisabled = true;
627
665
  this._logger.warn(`transport worker unavailable; using local transport: ${error instanceof Error ? error.message : String(error)}`);
628
666
  }
629
667
  }
668
+ _disableNetworkWorker(worker, error) {
669
+ if (this._worker !== worker)
670
+ return;
671
+ const wasConnected = this._workerConnected;
672
+ this._worker = null;
673
+ this._workerReady = false;
674
+ if (this._workerReadyTimer !== null) {
675
+ clearTimeout(this._workerReadyTimer);
676
+ this._workerReadyTimer = null;
677
+ }
678
+ this._workerDisabled = true;
679
+ this._workerConnected = false;
680
+ this._workerConnecting = false;
681
+ this._workerGeneration = null;
682
+ this._workerBufferedEvents = [];
683
+ for (const pending of this._workerPending.values()) {
684
+ if (pending.timer !== null)
685
+ clearTimeout(pending.timer);
686
+ pending.reject(error);
687
+ }
688
+ this._workerPending.clear();
689
+ void worker.terminate().catch(() => { });
690
+ if (wasConnected) {
691
+ this._dispatcher.enqueue('connection.error', { error });
692
+ this._dispatcher.enqueue('_transport.disconnect', { error, closeCode: 1006 });
693
+ }
694
+ else {
695
+ this._logger.warn(`transport worker unavailable; using local transport: ${error.message}`);
696
+ }
697
+ }
630
698
  _ensureNetworkWorker() {
631
- if (this._worker || !isMainThread || process.env.VITEST || process.env.AUN_TRANSPORT_LOCAL === '1')
699
+ if (this._worker || this._workerDisabled || !isMainThread || process.env.VITEST || process.env.AUN_TRANSPORT_LOCAL === '1')
632
700
  return;
633
701
  this._startNetworkWorker(this._workerOptions);
634
702
  const worker = this._worker;
635
703
  if (!worker)
636
704
  return;
637
- worker.postMessage({ type: 'set_timeout', value: this._timeout });
638
- worker.postMessage({ type: 'set_connect_timeout', value: this._connectTimeout });
639
- worker.postMessage({ type: 'set_trace_mode', value: this._traceMode });
705
+ try {
706
+ worker.postMessage({ type: 'set_timeout', value: this._timeout });
707
+ worker.postMessage({ type: 'set_connect_timeout', value: this._connectTimeout });
708
+ worker.postMessage({ type: 'set_trace_mode', value: this._traceMode });
709
+ }
710
+ catch (error) {
711
+ this._disableNetworkWorker(worker, error instanceof Error ? error : new Error(String(error)));
712
+ }
640
713
  }
641
714
  _dnsFallbackSnapshot(url) {
642
715
  if (!this._dnsNet)
@@ -702,6 +775,10 @@ export class RPCTransport {
702
775
  let posted = false;
703
776
  const promise = new Promise((resolve, reject) => {
704
777
  const timer = timeoutMs === null ? null : setTimeout(() => {
778
+ if (!this._workerReady && this._worker === worker) {
779
+ this._disableNetworkWorker(worker, new ConnectionError('transport worker startup timeout'));
780
+ return;
781
+ }
705
782
  this._workerPending.delete(id);
706
783
  if (posted) {
707
784
  try {
@@ -720,10 +797,7 @@ export class RPCTransport {
720
797
  posted = true;
721
798
  }
722
799
  catch (error) {
723
- this._workerPending.delete(id);
724
- if (timer !== null)
725
- clearTimeout(timer);
726
- reject(error);
800
+ this._disableNetworkWorker(worker, error instanceof Error ? error : new Error(String(error)));
727
801
  }
728
802
  };
729
803
  if (command.type === 'call')
@@ -753,7 +827,13 @@ export class RPCTransport {
753
827
  setTimeout(timeout) {
754
828
  this._timeout = timeout;
755
829
  if (this._worker) {
756
- this._worker.postMessage({ type: 'set_timeout', value: timeout });
830
+ const worker = this._worker;
831
+ try {
832
+ worker.postMessage({ type: 'set_timeout', value: timeout });
833
+ }
834
+ catch (error) {
835
+ this._disableNetworkWorker(worker, error instanceof Error ? error : new Error(String(error)));
836
+ }
757
837
  return;
758
838
  }
759
839
  }
@@ -761,7 +841,13 @@ export class RPCTransport {
761
841
  setConnectTimeout(timeout) {
762
842
  this._connectTimeout = timeout;
763
843
  if (this._worker) {
764
- this._worker.postMessage({ type: 'set_connect_timeout', value: timeout });
844
+ const worker = this._worker;
845
+ try {
846
+ worker.postMessage({ type: 'set_connect_timeout', value: timeout });
847
+ }
848
+ catch (error) {
849
+ this._disableNetworkWorker(worker, error instanceof Error ? error : new Error(String(error)));
850
+ }
765
851
  return;
766
852
  }
767
853
  }
@@ -787,7 +873,13 @@ export class RPCTransport {
787
873
  }
788
874
  this._traceMode = mode;
789
875
  if (this._worker) {
790
- this._worker.postMessage({ type: 'set_trace_mode', value: mode });
876
+ const worker = this._worker;
877
+ try {
878
+ worker.postMessage({ type: 'set_trace_mode', value: mode });
879
+ }
880
+ catch (error) {
881
+ this._disableNetworkWorker(worker, error instanceof Error ? error : new Error(String(error)));
882
+ }
791
883
  return;
792
884
  }
793
885
  }
@@ -920,6 +1012,9 @@ export class RPCTransport {
920
1012
  this._workerConnected = false;
921
1013
  this._workerGeneration = null;
922
1014
  this._workerBufferedEvents = [];
1015
+ if (this._workerDisabled && this._worker === null) {
1016
+ return this._enqueueActorStart(() => this._connectLocal(url));
1017
+ }
923
1018
  throw error;
924
1019
  }
925
1020
  }
@@ -1838,6 +1933,7 @@ export class RPCTransport {
1838
1933
  if (!isMainThread && Boolean(workerData?.aunShortRpcWorker) && parentPort) {
1839
1934
  const command = workerData;
1840
1935
  const controller = new AbortController();
1936
+ parentPort.postMessage({ type: 'ready', id: command.id });
1841
1937
  void executeShortRpcEnvelope(command.url, command.method, command.params, controller.signal)
1842
1938
  .then((result) => parentPort.postMessage({
1843
1939
  type: 'reply', id: command.id, ok: true, result,
@@ -1946,5 +2042,6 @@ if (!isMainThread && Boolean(workerData?.aunTransportWorker) && parentPort) {
1946
2042
  });
1947
2043
  }
1948
2044
  });
2045
+ parentPort.postMessage({ type: 'ready' });
1949
2046
  }
1950
2047
  //# sourceMappingURL=transport.js.map