@pisell/pisellos 2.2.122 → 2.2.124
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.
- package/dist/server/index.d.ts +64 -3
- package/dist/server/index.js +754 -190
- package/dist/server/modules/order/index.d.ts +25 -3
- package/dist/server/modules/order/index.js +282 -136
- package/lib/server/index.d.ts +64 -3
- package/lib/server/index.js +491 -33
- package/lib/server/modules/order/index.d.ts +25 -3
- package/lib/server/modules/order/index.js +105 -24
- package/package.json +1 -1
|
@@ -38,13 +38,16 @@ var import_BaseModule = require("../../../modules/BaseModule");
|
|
|
38
38
|
var import_types = require("./types");
|
|
39
39
|
var INDEXDB_STORE_NAME = "orders";
|
|
40
40
|
var ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY = "server_order_last_full_fetch_at";
|
|
41
|
+
var ORDER_SYNC_THROTTLE_MS_STORAGE_KEY = "order_sync_throttle_ms";
|
|
42
|
+
var DEFAULT_ORDER_SYNC_THROTTLE_MS = 2e3;
|
|
41
43
|
var OrderModule = class extends import_BaseModule.BaseModule {
|
|
42
44
|
constructor(name, version) {
|
|
43
45
|
super(name, version);
|
|
44
46
|
this.defaultName = "order";
|
|
45
47
|
this.defaultVersion = "1.0.0";
|
|
46
48
|
this.pendingSyncMessages = [];
|
|
47
|
-
this.
|
|
49
|
+
this.isProcessingSyncBatch = false;
|
|
50
|
+
this.isIdlePhase = true;
|
|
48
51
|
// Map<resource_id, OrderId[]> 资源到订单的倒排索引
|
|
49
52
|
this.resourceIdIndex = /* @__PURE__ */ new Map();
|
|
50
53
|
}
|
|
@@ -149,6 +152,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
149
152
|
} catch {
|
|
150
153
|
}
|
|
151
154
|
}
|
|
155
|
+
getOrderSyncThrottleMs() {
|
|
156
|
+
const raw = localStorage.getItem(ORDER_SYNC_THROTTLE_MS_STORAGE_KEY);
|
|
157
|
+
if (raw !== null) {
|
|
158
|
+
const parsed = Number(raw);
|
|
159
|
+
if (Number.isFinite(parsed) && parsed >= 0)
|
|
160
|
+
return parsed;
|
|
161
|
+
}
|
|
162
|
+
return DEFAULT_ORDER_SYNC_THROTTLE_MS;
|
|
163
|
+
}
|
|
152
164
|
async preload() {
|
|
153
165
|
const getData = async () => {
|
|
154
166
|
const orders = await this.loadOrdersByServer();
|
|
@@ -181,18 +193,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
181
193
|
if (this.orderDataSource) {
|
|
182
194
|
try {
|
|
183
195
|
const data = await this.orderDataSource.run({
|
|
184
|
-
|
|
196
|
+
sse: {
|
|
185
197
|
query: this.store.createdAtQuery
|
|
186
198
|
}
|
|
187
199
|
});
|
|
188
200
|
orderList = data || [];
|
|
189
|
-
this.logInfo("loadOrdersByServer
|
|
201
|
+
this.logInfo("loadOrdersByServer-SSE拉取成功", {
|
|
190
202
|
count: orderList.length
|
|
191
203
|
});
|
|
192
204
|
this.markOrderPulledAtNow();
|
|
193
205
|
} catch {
|
|
194
206
|
orderList = [];
|
|
195
|
-
this.logInfo("loadOrdersByServer
|
|
207
|
+
this.logInfo("loadOrdersByServer-SSE拉取失败,回退为空数组");
|
|
196
208
|
}
|
|
197
209
|
}
|
|
198
210
|
await this.saveOrdersToSQLite(orderList);
|
|
@@ -206,6 +218,22 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
206
218
|
const ids = this.resourceIdIndex.get(String(resourceId)) || [];
|
|
207
219
|
return ids.map((id) => this.store.map.get(id)).filter((order) => !!order);
|
|
208
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* 通过 SSE 按自定义 query 拉取订单(支持 select/with 精简字段)
|
|
223
|
+
*/
|
|
224
|
+
async fetchOrdersBySSE(query = {}) {
|
|
225
|
+
if (!this.orderDataSource)
|
|
226
|
+
return [];
|
|
227
|
+
try {
|
|
228
|
+
const data = await this.orderDataSource.run({ sse: { query } });
|
|
229
|
+
return data || [];
|
|
230
|
+
} catch (error) {
|
|
231
|
+
this.logError("fetchOrdersBySSE-失败", {
|
|
232
|
+
error: error instanceof Error ? error.message : String(error)
|
|
233
|
+
});
|
|
234
|
+
return [];
|
|
235
|
+
}
|
|
236
|
+
}
|
|
209
237
|
getRoutes() {
|
|
210
238
|
return [];
|
|
211
239
|
}
|
|
@@ -215,6 +243,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
215
243
|
clearTimeout(this.syncTimer);
|
|
216
244
|
this.syncTimer = void 0;
|
|
217
245
|
}
|
|
246
|
+
this.isProcessingSyncBatch = false;
|
|
218
247
|
this.pendingSyncMessages = [];
|
|
219
248
|
if ((_a = this.orderDataSource) == null ? void 0 : _a.destroy)
|
|
220
249
|
this.orderDataSource.destroy();
|
|
@@ -287,50 +316,92 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
287
316
|
this.orderDataSource = new OrderDataSourceClass();
|
|
288
317
|
}
|
|
289
318
|
/**
|
|
290
|
-
* 初始化 pubsub
|
|
319
|
+
* 初始化 pubsub 订阅,监听订单变更(纯订阅,不拉数据;全量 SSE 由 loadOrdersByServer 负责)
|
|
291
320
|
*/
|
|
292
321
|
setupOrderSync() {
|
|
293
322
|
if (!this.orderDataSource)
|
|
294
323
|
return;
|
|
295
|
-
|
|
296
|
-
const syncPayload = {
|
|
324
|
+
this.orderDataSource.run({
|
|
297
325
|
pubsub: {
|
|
298
326
|
callback: (res) => {
|
|
327
|
+
console.log("orderDataSource");
|
|
328
|
+
const pubsubReceivedAt = Date.now();
|
|
299
329
|
const message = this.normalizeOrderSyncMessage(res);
|
|
300
330
|
if (!message)
|
|
301
331
|
return;
|
|
332
|
+
message._pubsubReceivedAt = pubsubReceivedAt;
|
|
302
333
|
this.pendingSyncMessages.push(message);
|
|
334
|
+
const throttleMs = this.getOrderSyncThrottleMs();
|
|
303
335
|
this.logInfo("orderSync-收到消息并入队", {
|
|
304
336
|
id: message.id ?? null,
|
|
305
337
|
order_id: message.order_id ?? null,
|
|
306
338
|
type: message.type ?? null,
|
|
307
339
|
pendingCount: this.pendingSyncMessages.length,
|
|
308
|
-
|
|
340
|
+
throttleMs,
|
|
341
|
+
pubsubReceivedAt: new Date(pubsubReceivedAt).toISOString()
|
|
309
342
|
});
|
|
310
|
-
|
|
311
|
-
clearTimeout(this.syncTimer);
|
|
312
|
-
this.syncTimer = setTimeout(() => {
|
|
313
|
-
this.processOrderSyncMessages();
|
|
314
|
-
}, this.ORDER_SYNC_DEBOUNCE_MS);
|
|
343
|
+
this.scheduleOrderSyncThrottle();
|
|
315
344
|
}
|
|
316
345
|
}
|
|
317
|
-
};
|
|
318
|
-
syncPayload.http = {
|
|
319
|
-
query: this.store.createdAtQuery,
|
|
320
|
-
skipHttp: shouldSkipHttpPull
|
|
321
|
-
};
|
|
322
|
-
this.orderDataSource.run(syncPayload).then(() => {
|
|
323
|
-
if (!shouldSkipHttpPull)
|
|
324
|
-
this.markOrderPulledAtNow();
|
|
325
346
|
}).catch(() => {
|
|
326
347
|
});
|
|
327
348
|
}
|
|
328
349
|
/**
|
|
329
|
-
*
|
|
350
|
+
* 调度订单同步节流窗口(leading-edge throttle):
|
|
351
|
+
* - 空闲状态下收到的第一条消息立即触发批处理,无需等待;
|
|
352
|
+
* - 首条处理后进入冷却窗口,窗口期间的后续消息聚合,窗口结束后批量处理;
|
|
353
|
+
* - 若当前批处理执行中,则由批处理结束后决定是否开启下一轮窗口。
|
|
354
|
+
*/
|
|
355
|
+
scheduleOrderSyncThrottle() {
|
|
356
|
+
if (this.isProcessingSyncBatch)
|
|
357
|
+
return;
|
|
358
|
+
if (this.isIdlePhase) {
|
|
359
|
+
this.isIdlePhase = false;
|
|
360
|
+
this.logInfo("orderSync-首条消息立即触发处理");
|
|
361
|
+
void this.flushOrderSyncMessagesByThrottle();
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
if (this.syncTimer)
|
|
365
|
+
return;
|
|
366
|
+
const throttleMs = this.getOrderSyncThrottleMs();
|
|
367
|
+
this.syncTimer = setTimeout(() => {
|
|
368
|
+
this.syncTimer = void 0;
|
|
369
|
+
void this.flushOrderSyncMessagesByThrottle();
|
|
370
|
+
}, throttleMs);
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* 执行一次节流批处理并在需要时续约下一轮窗口。
|
|
374
|
+
* 批处理完成且无后续消息时恢复空闲状态,下一条消息将立即触发。
|
|
375
|
+
*/
|
|
376
|
+
async flushOrderSyncMessagesByThrottle() {
|
|
377
|
+
if (this.isProcessingSyncBatch)
|
|
378
|
+
return;
|
|
379
|
+
if (this.pendingSyncMessages.length === 0) {
|
|
380
|
+
this.isIdlePhase = true;
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
this.isProcessingSyncBatch = true;
|
|
384
|
+
try {
|
|
385
|
+
await this.processOrderSyncMessages();
|
|
386
|
+
} finally {
|
|
387
|
+
this.isProcessingSyncBatch = false;
|
|
388
|
+
if (this.pendingSyncMessages.length > 0) {
|
|
389
|
+
this.scheduleOrderSyncThrottle();
|
|
390
|
+
} else {
|
|
391
|
+
this.isIdlePhase = true;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* 处理节流窗口内聚合后的同步消息批次
|
|
330
397
|
*
|
|
331
398
|
* 后端统一发送 change 消息,不再区分新增/编辑/删除。
|
|
332
399
|
* - 单条(id/order_id):若携带 body/data 则直接 upsert 到本地
|
|
333
400
|
* - 批量(ids):通过 HTTP 按 ids 增量拉取,再 merge 到本地
|
|
401
|
+
*
|
|
402
|
+
* @example
|
|
403
|
+
* // pending 队列中存在 8 条消息时,仅处理一次批次并统一 merge
|
|
404
|
+
* await this.processOrderSyncMessages()
|
|
334
405
|
*/
|
|
335
406
|
async processOrderSyncMessages() {
|
|
336
407
|
var _a;
|
|
@@ -338,8 +409,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
338
409
|
this.pendingSyncMessages = [];
|
|
339
410
|
if (messages.length === 0)
|
|
340
411
|
return;
|
|
412
|
+
const batchProcessStartAt = Date.now();
|
|
413
|
+
const earliestReceivedAt = Math.min(
|
|
414
|
+
...messages.map((m) => m._pubsubReceivedAt ?? batchProcessStartAt)
|
|
415
|
+
);
|
|
341
416
|
this.logInfo("processOrderSyncMessages-开始", {
|
|
342
|
-
messageCount: messages.length
|
|
417
|
+
messageCount: messages.length,
|
|
418
|
+
earliestReceivedAt: new Date(earliestReceivedAt).toISOString(),
|
|
419
|
+
batchProcessStartAt: new Date(batchProcessStartAt).toISOString(),
|
|
420
|
+
waitDurationMs: batchProcessStartAt - earliestReceivedAt
|
|
343
421
|
});
|
|
344
422
|
const upsertOrders = /* @__PURE__ */ new Map();
|
|
345
423
|
const refreshIds = [];
|
|
@@ -375,9 +453,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
375
453
|
}
|
|
376
454
|
if (upsertList.length === 0 && uniqueRefreshIds.length === 0)
|
|
377
455
|
return;
|
|
456
|
+
const batchProcessEndAt = Date.now();
|
|
378
457
|
this.logInfo("processOrderSyncMessages-结束", {
|
|
379
458
|
upsertCount: upsertList.length,
|
|
380
|
-
refreshIdCount: uniqueRefreshIds.length
|
|
459
|
+
refreshIdCount: uniqueRefreshIds.length,
|
|
460
|
+
batchProcessDurationMs: batchProcessEndAt - batchProcessStartAt,
|
|
461
|
+
totalFromPubsubToProcessedMs: batchProcessEndAt - earliestReceivedAt
|
|
381
462
|
});
|
|
382
463
|
await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
383
464
|
}
|