Explorar el Código

Avoid duplicate cancel attempts via pending set

helium3@sina.com hace 2 meses
padre
commit
954655a205
Se han modificado 1 ficheros con 23 adiciones y 4 borrados
  1. 23 4
      packages/strategies/src/gridMaker.ts

+ 23 - 4
packages/strategies/src/gridMaker.ts

@@ -66,6 +66,7 @@ export class GridMaker {
   private resetting = false;
   private consecutivePlaceFailures = 0;
   private needsReinit = false;
+  private readonly pendingCancellations = new Set<string>();
 
   constructor(
     private config: GridConfig,
@@ -134,12 +135,16 @@ export class GridMaker {
 
           // 从网格中删除这个层级
           this.grids.delete(index);
-
+          this.pendingCancellations.delete(orderId);
           // 标记需要重新初始化(在下次 tick 时补单)
           this.needsReinit = true;
-          break;
+          return;
         }
       }
+      if (this.pendingCancellations.delete(orderId)) {
+        this.logger.debug({ orderId }, 'Cancellation confirmed for order not present in grid (likely pre-removed)');
+      }
+      return;
     }
   }
 
@@ -404,7 +409,12 @@ export class GridMaker {
     const tolerancePx = this.tickSize > 0 ? this.tickSize : levels.length > 0 ? Math.abs(levels[0].px) * 1e-6 : 1e-6;
     const sizeToleranceBase = this.lotSize > 0 ? this.lotSize : 1e-8;
 
-    const activeLevels = Array.from(this.grids.values()).filter(level => level.orderId && !level.filled);
+    const activeLevels = Array.from(this.grids.values()).filter(
+      level =>
+        level.orderId &&
+        !level.filled &&
+        !this.pendingCancellations.has(level.orderId)
+    );
 
     for (const level of activeLevels) {
       const target = targetMap.get(level.index);
@@ -885,8 +895,15 @@ export class GridMaker {
   private async cancelGridLevel(level: GridLevel): Promise<void> {
     const orderId = level.orderId;
     if (!orderId) return;
+    if (this.pendingCancellations.has(orderId)) {
+      this.logger.debug({ orderId }, 'Cancel request skipped because it is already pending');
+      return;
+    }
     this.logger.debug({ orderId }, 'Canceling grid order');
     let cancelled = false;
+    const snapshot = { ...level };
+    this.pendingCancellations.add(orderId);
+    this.grids.delete(level.index);
     try {
       await this.router.cancel(orderId);
       cancelled = true;
@@ -920,11 +937,13 @@ export class GridMaker {
         cancelled = true;
       }
       if (!cancelled) {
+        // 还原本地状态,等待下次重试
+        this.grids.set(snapshot.index, snapshot);
         throw error;
       }
     } finally {
+      this.pendingCancellations.delete(orderId);
       if (cancelled) {
-        this.grids.delete(level.index);
         this.releaseOrder(orderId, level.clientId);
         this.logger.debug({ orderId }, 'Grid order cancel confirmed');
       }