All files / src/bridge EngineConcurrencyController.ts

94.11% Statements 16/17
72.72% Branches 16/22
100% Functions 4/4
100% Lines 16/16

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59              4x           4x     4x 4x                     7x   7x   2x 2x 2x 2x   2x       7x       1x       3x 1x 2x              
import { EngineStatus } from "../types.js";
 
/**
 * 複数エンジンの同時実行を制御するコントローラー。
 * 特にモバイル環境等でメモリを保護するため、アクティブなエンジン数を制限します。
 */
export class EngineConcurrencyController {
  private activeEngines = new Set<string>();
  private maxActive: number;
 
  constructor(maxActive?: number) {
    // デフォルトは 2 (1つがメイン、1つがバックグラウンド解析用など)
    // deviceMemory が低い場合は 1 に制限
    const g = globalThis as unknown as {
      navigator?: { deviceMemory?: number };
    };
    const ram = g.navigator?.deviceMemory || 4;
    this.maxActive = maxActive || (ram < 4 ? 1 : 2);
  }
 
  /**
   * エンジンがアクティブ(busy)になる許可を求めます。
   * 上限に達している場合は、古いエンジンを停止(サスペンド)させるか、待機させます。
   */
  public async requestActive(
    engineId: string,
    onSuspend?: (targetId: string) => Promise<void>,
  ): Promise<void> {
    Iif (this.activeEngines.has(engineId)) return;
 
    if (this.activeEngines.size >= this.maxActive) {
      // 最も古いアクティブエンジンを特定(簡易的に最初の要素)
      const oldest = this.activeEngines.values().next().value;
      Eif (oldest && oldest !== engineId) {
        Eif (onSuspend) {
          await onSuspend(oldest);
        }
        this.activeEngines.delete(oldest);
      }
    }
 
    this.activeEngines.add(engineId);
  }
 
  public releaseActive(engineId: string): void {
    this.activeEngines.delete(engineId);
  }
 
  public updateStatus(engineId: string, status: EngineStatus): void {
    if (status === "busy") {
      this.activeEngines.add(engineId);
    } else if (Estatus === "ready" || status === "error") {
      // 停止した場合は管理から外す(サスペンドの余地を作る)
      // ただし、即座に消すとリクエスト時の優先順位がわからなくなるため、
      // 実際には LRU キュー等で管理するのが望ましい。
    }
  }
}