@iobroker/js-controller-adapter 7.0.8-alpha.8-20251127-036be0224 → 7.1.0

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.
@@ -531,56 +531,67 @@ class AdapterClass extends import_node_events.EventEmitter {
531
531
  return;
532
532
  }
533
533
  this.terminated = true;
534
- this.pluginHandler && this.pluginHandler.destroyAll();
535
- if (this._reportInterval) {
536
- clearInterval(this._reportInterval);
537
- this._reportInterval = null;
538
- }
539
- if (this._restartScheduleJob) {
540
- this._restartScheduleJob.cancel();
541
- this._restartScheduleJob = null;
542
- }
543
- let _reason = "Without reason";
544
- let _exitCode;
545
- if (typeof reason === "number") {
546
- exitCode = reason;
547
- _reason = "Without reason";
548
- } else if (reason && typeof reason === "string") {
549
- _reason = reason;
550
- }
551
- if (typeof exitCode !== "number") {
552
- _exitCode = !this._config.isInstall ? import_js_controller_common.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION : import_js_controller_common.EXIT_CODES.NO_ERROR;
553
- } else {
554
- _exitCode = exitCode;
555
- }
556
- const isNotCritical = _exitCode === import_js_controller_common.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION || _exitCode === import_js_controller_common.EXIT_CODES.START_IMMEDIATELY_AFTER_STOP || _exitCode === import_js_controller_common.EXIT_CODES.NO_ERROR;
557
- const text = `${this.namespaceLog} Terminated (${import_validator.Validator.getErrorText(_exitCode)}): ${_reason}`;
558
- if (isNotCritical) {
559
- this._logger.info(text);
560
- } else {
561
- this._logger.warn(text);
562
- }
563
- setTimeout(async () => {
564
- if (this.#states) {
565
- try {
566
- await this.#states.destroy();
567
- } catch {
568
- }
534
+ let shutdownStarted = false;
535
+ const shutdownLogic = () => {
536
+ if (shutdownStarted) {
537
+ return;
569
538
  }
570
- if (this.#objects) {
571
- try {
572
- await this.#objects.destroy();
573
- } catch {
574
- }
539
+ shutdownStarted = true;
540
+ if (this._reportInterval) {
541
+ clearInterval(this._reportInterval);
542
+ this._reportInterval = null;
543
+ }
544
+ if (this._restartScheduleJob) {
545
+ this._restartScheduleJob.cancel();
546
+ this._restartScheduleJob = null;
547
+ }
548
+ let _reason = "Without reason";
549
+ let _exitCode;
550
+ if (typeof reason === "number") {
551
+ exitCode = reason;
552
+ _reason = "Without reason";
553
+ } else if (reason && typeof reason === "string") {
554
+ _reason = reason;
555
+ }
556
+ if (typeof exitCode !== "number") {
557
+ _exitCode = !this._config.isInstall ? import_js_controller_common.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION : import_js_controller_common.EXIT_CODES.NO_ERROR;
558
+ } else {
559
+ _exitCode = exitCode;
575
560
  }
576
- if (this.startedInCompactMode) {
577
- this.emit("exit", _exitCode, reason);
578
- this.#states = null;
579
- this.#objects = null;
561
+ const isNotCritical = _exitCode === import_js_controller_common.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION || _exitCode === import_js_controller_common.EXIT_CODES.START_IMMEDIATELY_AFTER_STOP || _exitCode === import_js_controller_common.EXIT_CODES.NO_ERROR;
562
+ const text = `${this.namespaceLog} Terminated (${import_validator.Validator.getErrorText(_exitCode)}): ${_reason}`;
563
+ if (isNotCritical) {
564
+ this._logger.info(text);
580
565
  } else {
581
- process.exit(_exitCode);
566
+ this._logger.warn(text);
582
567
  }
583
- }, 500);
568
+ setTimeout(async () => {
569
+ if (this.#states) {
570
+ try {
571
+ await this.#states.destroy();
572
+ } catch {
573
+ }
574
+ }
575
+ if (this.#objects) {
576
+ try {
577
+ await this.#objects.destroy();
578
+ } catch {
579
+ }
580
+ }
581
+ if (this.startedInCompactMode) {
582
+ this.emit("exit", _exitCode, reason);
583
+ this.#states = null;
584
+ this.#objects = null;
585
+ } else {
586
+ process.exit(_exitCode);
587
+ }
588
+ }, 500);
589
+ };
590
+ if (this.pluginHandler) {
591
+ this.pluginHandler.destroyAll().then(() => shutdownLogic()).catch(() => shutdownLogic());
592
+ } else {
593
+ shutdownLogic();
594
+ }
584
595
  }
585
596
  /**
586
597
  * Helper function to find next free port
@@ -1150,22 +1161,25 @@ class AdapterClass extends import_node_events.EventEmitter {
1150
1161
  }
1151
1162
  if (this.#states && updateAliveState) {
1152
1163
  this.outputCount++;
1153
- await this.#states.setState(`${id}.alive`, { val: false, ack: true, from: id });
1154
- if (!isPause) {
1155
- this._logger.info(`${this.namespaceLog} terminating`);
1156
- }
1157
- this.terminate(reason, exitCode);
1158
- } else {
1159
- if (!isPause) {
1160
- this._logger.info(`${this.namespaceLog} terminating`);
1164
+ try {
1165
+ await this.#states.setState(`${id}.alive`, { val: false, ack: true, from: id });
1166
+ } catch (e) {
1167
+ this._logger.error(`${this.namespaceLog} Cannot set alive state to false: ${e.message}`);
1161
1168
  }
1162
- this.terminate(reason, exitCode);
1163
1169
  }
1170
+ if (!isPause) {
1171
+ this._logger.info(`${this.namespaceLog} terminating`);
1172
+ }
1173
+ this.terminate(reason, exitCode);
1164
1174
  };
1165
1175
  if (this.adapterReady) {
1166
1176
  if (typeof this._options.unload === "function") {
1167
1177
  if (this._options.unload.length >= 1) {
1168
- this._options.unload(finishUnload);
1178
+ try {
1179
+ this._options.unload(finishUnload);
1180
+ } catch {
1181
+ finishUnload();
1182
+ }
1169
1183
  } else {
1170
1184
  const unloadPromise = this._options.unload();
1171
1185
  if (unloadPromise instanceof Promise) {
@@ -1183,20 +1197,16 @@ class AdapterClass extends import_node_events.EventEmitter {
1183
1197
  }
1184
1198
  }
1185
1199
  setTimeout(() => {
1186
- if (this.#states) {
1187
- finishUnload();
1188
- setTimeout(() => {
1189
- if (!isPause) {
1190
- this._logger.info(`${this.namespaceLog} terminating with timeout`);
1191
- }
1192
- this.terminate(exitCode);
1193
- }, 1e3);
1194
- } else {
1200
+ if (!this.#states) {
1201
+ updateAliveState = false;
1202
+ }
1203
+ const terminate = () => {
1195
1204
  if (!isPause) {
1196
1205
  this._logger.info(`${this.namespaceLog} terminating`);
1197
1206
  }
1198
1207
  this.terminate(exitCode);
1199
- }
1208
+ };
1209
+ finishUnload().then(terminate, terminate);
1200
1210
  }, this.common?.stopTimeout || 500);
1201
1211
  }
1202
1212
  }
@@ -1469,7 +1479,8 @@ class AdapterClass extends import_node_events.EventEmitter {
1469
1479
  }
1470
1480
  /**
1471
1481
  * delays the fulfillment of the promise the amount of time.
1472
- * it will not fulfill during and after adapter shutdown
1482
+ * It will directly fulfill without any delay during and after adapter shutdown
1483
+ * (e.g. in an unload method)
1473
1484
  *
1474
1485
  * @param timeout - timeout in milliseconds
1475
1486
  * @returns promise when timeout is over
@@ -7215,7 +7226,6 @@ class AdapterClass extends import_node_events.EventEmitter {
7215
7226
  exitCode: import_js_controller_common.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION,
7216
7227
  updateAliveState: false
7217
7228
  });
7218
- setTimeout(() => this.terminate(import_js_controller_common.EXIT_CODES.ADAPTER_REQUESTED_TERMINATION), 4e3);
7219
7229
  }
7220
7230
  }
7221
7231
  }
@@ -7327,10 +7337,10 @@ class AdapterClass extends import_node_events.EventEmitter {
7327
7337
  if (!this.pluginHandler.isPluginInstantiated(pluginName)) {
7328
7338
  this.pluginHandler.instantiatePlugin(pluginName, this.pluginHandler.getPluginConfig(pluginName) || {}, thisDir);
7329
7339
  this.pluginHandler.setDatabaseForPlugin(pluginName, this.#objects, this.#states);
7330
- this.pluginHandler.initPlugin(pluginName, this.adapterConfig || {});
7340
+ await this.pluginHandler.initPlugin(pluginName, this.adapterConfig || {});
7331
7341
  }
7332
7342
  } else {
7333
- if (!this.pluginHandler.destroy(pluginName)) {
7343
+ if (!await this.pluginHandler.destroy(pluginName)) {
7334
7344
  this._logger.info(`${this.namespaceLog} Plugin ${pluginName} could not be disabled. Please restart adapter to disable it.`);
7335
7345
  }
7336
7346
  }
@@ -7393,8 +7403,8 @@ class AdapterClass extends import_node_events.EventEmitter {
7393
7403
  if (this.connected) {
7394
7404
  return;
7395
7405
  }
7396
- this._logger.warn(`${this.namespaceLog} Cannot connect/reconnect to states DB. Terminating`);
7397
- this.terminate(import_js_controller_common.EXIT_CODES.NO_ERROR);
7406
+ this._logger.warn(`${this.namespaceLog} Cannot connect/reconnect to states DB. Stopping adapter.`);
7407
+ this._stop({ exitCode: import_js_controller_common.EXIT_CODES.NO_ERROR, updateAliveState: false });
7398
7408
  }, 5e3);
7399
7409
  }
7400
7410
  });
@@ -7454,8 +7464,8 @@ class AdapterClass extends import_node_events.EventEmitter {
7454
7464
  if (this.connected) {
7455
7465
  return;
7456
7466
  }
7457
- this._logger.warn(`${this.namespaceLog} Cannot connect/reconnect to objects DB. Terminating`);
7458
- this.terminate(import_js_controller_common.EXIT_CODES.NO_ERROR);
7467
+ this._logger.warn(`${this.namespaceLog} Cannot connect/reconnect to objects DB. Stopping adapter.`);
7468
+ this._stop({ exitCode: import_js_controller_common.EXIT_CODES.NO_ERROR, updateAliveState: false });
7459
7469
  }, 4e3);
7460
7470
  },
7461
7471
  change: async (id, obj) => {
@@ -7466,7 +7476,6 @@ class AdapterClass extends import_node_events.EventEmitter {
7466
7476
  if (id === `system.adapter.${this.namespace}` && obj?.common?.enabled === false) {
7467
7477
  this._logger.info(`${this.namespaceLog} Adapter is disabled => stop`);
7468
7478
  this._stop();
7469
- setTimeout(() => this.terminate(import_js_controller_common.EXIT_CODES.NO_ERROR), 4e3);
7470
7479
  return;
7471
7480
  }
7472
7481
  if (id === "system.config" && obj?.common && (this._options.useFormatDate || this.defaultHistory !== void 0)) {
@@ -7851,21 +7860,23 @@ class AdapterClass extends import_node_events.EventEmitter {
7851
7860
  }
7852
7861
  }
7853
7862
  async _exceptionHandler(err, isUnhandledRejection) {
7854
- if (typeof this._options.error === "function") {
7855
- try {
7856
- const wasHandled = this._options.error(err);
7857
- if (wasHandled === true) {
7858
- return;
7863
+ if (!this._stopInProgress) {
7864
+ if (typeof this._options.error === "function") {
7865
+ try {
7866
+ const wasHandled = this._options.error(err);
7867
+ if (wasHandled === true) {
7868
+ return;
7869
+ }
7870
+ } catch (e) {
7871
+ console.error(`Error in adapter error handler: ${e.message}`);
7859
7872
  }
7860
- } catch (e) {
7861
- console.error(`Error in adapter error handler: ${e.message}`);
7862
7873
  }
7863
- }
7864
- if (this.getPortRunning && err?.message === "listen EADDRINUSE") {
7865
- const { host, port, callback } = this.getPortRunning;
7866
- this._logger.warn(`${this.namespaceLog} Port ${port}${host ? ` for host ${host}` : ""} is in use. Get next`);
7867
- setImmediate(() => this.getPort(port + 1, host, callback));
7868
- return;
7874
+ if (this.getPortRunning && err?.message === "listen EADDRINUSE") {
7875
+ const { host, port, callback } = this.getPortRunning;
7876
+ this._logger.warn(`${this.namespaceLog} Port ${port}${host ? ` for host ${host}` : ""} is in use. Get next`);
7877
+ setImmediate(() => this.getPort(port + 1, host, callback));
7878
+ return;
7879
+ }
7869
7880
  }
7870
7881
  if (isUnhandledRejection) {
7871
7882
  this._logger.error(`${this.namespaceLog} Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch().`);
@@ -7874,7 +7885,7 @@ class AdapterClass extends import_node_events.EventEmitter {
7874
7885
  if (err?.stack) {
7875
7886
  this._logger.error(`${this.namespaceLog} ${err.stack}`);
7876
7887
  }
7877
- if (err) {
7888
+ if (err && !this._stopInProgress) {
7878
7889
  const message = err.code ? `Exception-Code: ${err.code}: ${err.message}` : err.message;
7879
7890
  this._logger.error(`${this.namespaceLog} ${message}`);
7880
7891
  try {
@@ -7882,16 +7893,17 @@ class AdapterClass extends import_node_events.EventEmitter {
7882
7893
  } catch {
7883
7894
  }
7884
7895
  }
7885
- try {
7886
- this._stop({
7887
- isPause: false,
7888
- isScheduled: false,
7889
- exitCode: import_js_controller_common.EXIT_CODES.UNCAUGHT_EXCEPTION,
7890
- updateAliveState: false
7891
- });
7892
- setTimeout(() => this.terminate(import_js_controller_common.EXIT_CODES.UNCAUGHT_EXCEPTION), 1e3);
7893
- } catch (e) {
7894
- this._logger.error(`${this.namespaceLog} exception by stop: ${e ? e.message : e}`);
7896
+ if (!this._stopInProgress) {
7897
+ try {
7898
+ this._stop({
7899
+ isPause: false,
7900
+ isScheduled: false,
7901
+ exitCode: import_js_controller_common.EXIT_CODES.UNCAUGHT_EXCEPTION,
7902
+ updateAliveState: false
7903
+ });
7904
+ } catch (e) {
7905
+ this._logger.error(`${this.namespaceLog} exception by stop: ${e ? e.message : e}`);
7906
+ }
7895
7907
  }
7896
7908
  }
7897
7909
  async _createInstancesObjects(instanceObj) {
@@ -8104,7 +8116,6 @@ class AdapterClass extends import_node_events.EventEmitter {
8104
8116
  // @ts-expect-error
8105
8117
  log: this._logger,
8106
8118
  iobrokerConfig: this._config,
8107
- // @ts-expect-error
8108
8119
  parentPackage: this.pack,
8109
8120
  controllerVersion
8110
8121
  };