@testdriverai/runner 7.9.10-test → 7.9.12-test

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.
@@ -164,6 +164,7 @@ class AblyService extends EventEmitter {
164
164
  this._sessionChannel = null;
165
165
  this._connected = false;
166
166
  this._statsInterval = null;
167
+ this._closed = false; // set to true in close() to suppress post-close events
167
168
  }
168
169
 
169
170
  /**
@@ -367,7 +368,10 @@ class AblyService extends EventEmitter {
367
368
  if (current === 'disconnected') {
368
369
  this._connected = false;
369
370
  this.emit('log', `Realtime connection: ${previous} → ${current}${reasonMsg ? ' — ' + reasonMsg : ''}${retryIn ? ' (retryIn=' + retryIn + 'ms)' : ''}`);
370
- this.emit('log', 'Ably disconnected will auto-reconnect');
371
+ // Suppress auto-reconnect message when we've already initiated a clean close
372
+ if (!this._closed) {
373
+ this.emit('log', 'Ably disconnected — will auto-reconnect');
374
+ }
371
375
  } else if (current === 'connected' && previous !== 'initialized') {
372
376
  if (!this._connected) {
373
377
  this._connected = true;
@@ -390,8 +394,8 @@ class AblyService extends EventEmitter {
390
394
  this.emit('log', `Realtime connection: ${previous} → ${current}${reasonMsg ? ' — ' + reasonMsg : ''}`);
391
395
  }
392
396
 
393
- // Capture exceptions for bad states
394
- if (current === 'failed' || current === 'suspended' || (current === 'disconnected' && reason)) {
397
+ // Capture exceptions for bad states — skip if we're in a clean close sequence
398
+ if (!this._closed && (current === 'failed' || current === 'suspended' || (current === 'disconnected' && reason))) {
395
399
  Sentry.withScope((scope) => {
396
400
  scope.setTag('ably.client', 'runner');
397
401
  scope.setTag('ably.state', current);
@@ -579,6 +583,10 @@ class AblyService extends EventEmitter {
579
583
  * so that missed commands are actually executed.
580
584
  */
581
585
  async _recoverFromDiscontinuity() {
586
+ // Don't attempt recovery after an intentional close — subscriptions are
587
+ // nulled out in close() and the channel is being torn down
588
+ if (this._closed) return;
589
+
582
590
  const subs = [
583
591
  { name: 'command', sub: this._commandSubscription, handler: this._onCommandMsg },
584
592
  { name: 'control', sub: this._controlSubscription, handler: this._onControlMsg },
@@ -668,6 +676,9 @@ class AblyService extends EventEmitter {
668
676
  * Disconnect from Ably and clean up.
669
677
  */
670
678
  async close() {
679
+ if (this._closed) return; // Prevent double-close
680
+ this._closed = true;
681
+
671
682
  this.emit('log', 'Closing realtime service...');
672
683
 
673
684
  this._stopReadySignal();
@@ -677,6 +688,11 @@ class AblyService extends EventEmitter {
677
688
  this._statsInterval = null;
678
689
  }
679
690
 
691
+ // Null out subscription refs so _recoverFromDiscontinuity won't replay
692
+ // messages on a channel that is about to be torn down
693
+ this._commandSubscription = null;
694
+ this._controlSubscription = null;
695
+
680
696
  try {
681
697
  if (this._sessionChannel) this._sessionChannel.detach();
682
698
  } catch { }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testdriverai/runner",
3
- "version": "7.9.10-test",
3
+ "version": "7.9.12-test",
4
4
  "description": "TestDriver Runner - Ably-based remote automation agent with Node.js automation",
5
5
  "main": "index.js",
6
6
  "bin": {