@hile/micro 2.0.3 → 2.0.5

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.
@@ -85,15 +85,16 @@ export class Application extends Server {
85
85
  // 这里不清理 topics 由业务方自己清理
86
86
  // 这里也不清理 declare 和 undeclare 由业务方自己清理
87
87
  return async () => {
88
+ this.stopped = true;
88
89
  for (const fallback of this.fallbacks) {
89
90
  fallback();
90
91
  }
91
92
  this.fallbacks.clear();
92
- this.stopped = true;
93
93
  if (this.reconnectTimeout) {
94
94
  clearTimeout(this.reconnectTimeout);
95
95
  this.reconnectTimeout = undefined;
96
96
  }
97
+ this.registry?.dispose();
97
98
  this.registry = undefined;
98
99
  await callback();
99
100
  };
@@ -105,6 +106,7 @@ export class Application extends Server {
105
106
  clearTimeout(this.reconnectTimeout);
106
107
  this.reconnectTimeout = setTimeout(() => {
107
108
  this.reconnectTimeout = undefined;
109
+ this.logger.debug('[reconnecting] %s:%d', this._registry_address.host, this._registry_address.port);
108
110
  void this.reconnectToRegistry().catch(() => {
109
111
  if (this.stopped)
110
112
  return;
@@ -140,6 +142,7 @@ export class Application extends Server {
140
142
  for (const [topic, callback] of this.topics) {
141
143
  await this.subscribe(topic, callback, true);
142
144
  }
145
+ this.logger.debug('[reconnected] %s:%d', this._registry_address.host, this._registry_address.port);
143
146
  })().finally(() => {
144
147
  this.registryReconnectPromise = undefined;
145
148
  });
package/dist/registry.js CHANGED
@@ -3,6 +3,7 @@ import { homedir } from 'node:os';
3
3
  import { resolve, join } from 'node:path';
4
4
  import { existsSync, mkdirSync, readdirSync, readFileSync, watch } from 'node:fs';
5
5
  import YAML from 'yaml';
6
+ import { createLogger } from '@hile/logger';
6
7
  /** 将 `host:port` 或 `[ipv6]:port` 形式的 key 解析为地址(端口取最后一个 `:` 之后) */
7
8
  export function parseAddressKey(key) {
8
9
  const i = key.lastIndexOf(':');
@@ -51,7 +52,12 @@ export class Registry extends Server {
51
52
  if (!existsSync(workspace)) {
52
53
  mkdirSync(workspace, { recursive: true });
53
54
  }
54
- super('registry', props);
55
+ super('registry', {
56
+ logger: props.logger ?? createLogger({
57
+ level: 'debug',
58
+ pretty: process.env.NODE_ENV !== 'production',
59
+ }), ...props
60
+ });
55
61
  this.workspace = workspace;
56
62
  this.events.on('connect', (client, extras) => {
57
63
  const key = client.host + ':' + client.port;
@@ -60,17 +66,19 @@ export class Registry extends Server {
60
66
  this.namespaces.set(namespace, new Set());
61
67
  }
62
68
  this.namespaces.get(namespace).add(key);
69
+ this.logger.debug('[connect] %s/%s', key, namespace);
63
70
  });
64
71
  this.events.on('disconnect', (client, extras) => {
65
72
  const key = client.host + ':' + client.port;
66
- // 清理 topic 中的关联
67
- for (const [topic, { publishers, subscribers }] of this.topics) {
68
- if (publishers.has(key))
73
+ // 清理 topic 中的关联(不删除 topic,保留 data 供后续 subscriber 使用)
74
+ for (const [, { publishers, subscribers }] of this.topics) {
75
+ if (publishers.has(key)) {
69
76
  publishers.delete(key);
70
- if (subscribers.has(key))
77
+ this.logger.debug('[delete publisher] %s', key);
78
+ }
79
+ if (subscribers.has(key)) {
71
80
  subscribers.delete(key);
72
- if (publishers.size === 0 && subscribers.size === 0) {
73
- this.topics.delete(topic);
81
+ this.logger.debug('[delete subscriber] %s', key);
74
82
  }
75
83
  }
76
84
  // 清理 namespace 中的关联
@@ -79,8 +87,10 @@ export class Registry extends Server {
79
87
  const keys = this.namespaces.get(namespace);
80
88
  if (keys.has(key)) {
81
89
  keys.delete(key);
90
+ this.logger.debug('[disconnect] %s/%s', key, namespace);
82
91
  if (keys.size === 0) {
83
92
  this.namespaces.delete(namespace);
93
+ this.logger.debug('[delete namespace] %s', namespace);
84
94
  }
85
95
  }
86
96
  }
@@ -186,6 +196,7 @@ export class Registry extends Server {
186
196
  entry.data = data.payload;
187
197
  publishers.add(key);
188
198
  this.publish(data.topic, data.payload);
199
+ this.logger.debug('[declare] %s/%s', key, data.topic);
189
200
  return Date.now();
190
201
  }));
191
202
  }
@@ -200,8 +211,10 @@ export class Registry extends Server {
200
211
  const i = publishers.size;
201
212
  if (publishers.has(key)) {
202
213
  publishers.delete(key);
214
+ this.logger.debug('[undeclare] %s/%s', key, data.topic);
203
215
  if (publishers.size === 0 && subscribers.size === 0) {
204
216
  this.topics.delete(data.topic);
217
+ this.logger.debug('[delete topic] %s', data.topic);
205
218
  }
206
219
  }
207
220
  return i - publishers.size;
@@ -216,6 +229,7 @@ export class Registry extends Server {
216
229
  const entry = this.topics.get(data.topic);
217
230
  const subscribers = entry.subscribers;
218
231
  subscribers.add(key);
232
+ this.logger.debug('[subscribe] %s/%s', key, data.topic);
219
233
  return entry.data;
220
234
  }));
221
235
  }
@@ -226,14 +240,11 @@ export class Registry extends Server {
226
240
  return 0;
227
241
  const entry = this.topics.get(data.topic);
228
242
  const subscribers = entry.subscribers;
229
- const publishers = entry.publishers;
230
243
  const i = subscribers.size;
231
244
  if (subscribers.has(key)) {
232
245
  subscribers.delete(key);
233
- if (subscribers.size === 0 && publishers.size === 0) {
234
- this.topics.delete(data.topic);
235
- }
236
246
  }
247
+ this.logger.debug('[unsubscribe] %s/%s', key, data.topic);
237
248
  return i - subscribers.size;
238
249
  }));
239
250
  }
package/dist/server.d.ts CHANGED
@@ -3,6 +3,7 @@ import { Client } from './client.js';
3
3
  import { IncomingMessage } from 'http';
4
4
  import { EventEmitter } from 'node:events';
5
5
  import type { Duplex } from "node:stream";
6
+ import type { Logger } from '@hile/logger';
6
7
  /** {@link MessageLoaderProps} 加上出站 WebSocket 宣告地址 */
7
8
  export type MicroServerProps = MessageLoaderProps & {
8
9
  /**
@@ -10,11 +11,16 @@ export type MicroServerProps = MessageLoaderProps & {
10
11
  * 缺省使用 `getLocalIPv4()`;若仍为 `undefined`(无可用 IPv4)则构造 {@link Server} 时抛错。
11
12
  */
12
13
  advertiseHost?: string;
14
+ /**
15
+ * 日志记录器
16
+ */
17
+ logger?: Logger;
13
18
  };
14
19
  export declare class Server extends MessageLoader {
15
20
  readonly namespace: string;
16
21
  private wss?;
17
22
  port?: number;
23
+ readonly logger: Logger | Console;
18
24
  readonly clients: Map<string, Client>;
19
25
  private readonly announceHost;
20
26
  readonly events: EventEmitter<any>;
package/dist/server.js CHANGED
@@ -9,6 +9,7 @@ export class Server extends MessageLoader {
9
9
  namespace;
10
10
  wss;
11
11
  port;
12
+ logger;
12
13
  clients = new Map();
13
14
  announceHost;
14
15
  events = new EventEmitter();
@@ -16,7 +17,7 @@ export class Server extends MessageLoader {
16
17
  return this.announceHost;
17
18
  }
18
19
  constructor(namespace, props = {}) {
19
- const { advertiseHost, ...loaderProps } = props;
20
+ const { advertiseHost, logger, ...loaderProps } = props;
20
21
  super(loaderProps);
21
22
  this.namespace = namespace;
22
23
  const resolved = advertiseHost?.trim() || getLocalIPv4();
@@ -24,6 +25,7 @@ export class Server extends MessageLoader {
24
25
  throw new Error('Unable to resolve advertise host for @hile/micro Server: pass `advertiseHost` (e.g. "127.0.0.1") in constructor options, or ensure getLocalIPv4() returns an address.');
25
26
  }
26
27
  this.announceHost = resolved;
28
+ this.logger = logger ?? console;
27
29
  this.events.on('connect', (client, extras) => {
28
30
  client.events.emit('connect', extras);
29
31
  });
@@ -133,12 +135,12 @@ export class Server extends MessageLoader {
133
135
  this.wss = new WebSocketServer({ noServer: true });
134
136
  }
135
137
  return async () => {
136
- const toDispose = [...this.clients.values()];
137
- for (const client of toDispose) {
138
- client.dispose();
139
- }
140
- this.clients.clear();
141
138
  if (this.wss) {
139
+ // terminate 立即销毁 socket,不等待对端 close frame
140
+ // 避免 graceful close 时对端无响应导致 HTTP server 无法关闭
141
+ for (const ws of [...this.wss.clients]) {
142
+ ws.terminate();
143
+ }
142
144
  await new Promise((resolve, reject) => {
143
145
  this.wss.close((err) => {
144
146
  if (err)
@@ -147,6 +149,11 @@ export class Server extends MessageLoader {
147
149
  });
148
150
  });
149
151
  }
152
+ const toDispose = [...this.clients.values()];
153
+ for (const client of toDispose) {
154
+ client.dispose();
155
+ }
156
+ this.clients.clear();
150
157
  this.wss = undefined;
151
158
  this.port = undefined;
152
159
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hile/micro",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -23,11 +23,12 @@
23
23
  "vitest": "^4.0.18"
24
24
  },
25
25
  "dependencies": {
26
+ "@hile/logger": "^2.0.1",
26
27
  "@hile/message-loader": "^2.0.1",
27
28
  "@hile/message-ws": "^2.0.3",
28
29
  "internal-ip": "^9.0.0",
29
30
  "ws": "^8.21.0",
30
31
  "yaml": "^2.9.0"
31
32
  },
32
- "gitHead": "d2495d1c31f5c5fbc25c9d447c8f32b484ab0340"
33
+ "gitHead": "aaa46af05d9fe0d658b4f7a8d54ad8da088a10f6"
33
34
  }