claw-subagent-service 0.0.51 → 0.0.52

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claw-subagent-service",
3
- "version": "0.0.51",
3
+ "version": "0.0.52",
4
4
  "description": "虾说智能助手",
5
5
  "main": "cli.js",
6
6
  "bin": {
@@ -196,6 +196,30 @@ function startOpenClawGateway(log) {
196
196
  }
197
197
 
198
198
  class OpenClawClient {
199
+ // 全局并发限制:同时最多运行 N 个 openclaw agent 进程
200
+ static maxConcurrency = 2;
201
+ static runningCount = 0;
202
+ static waitQueue = [];
203
+ // Session 级串行锁:确保同一 session 不会并发 spawn 多个进程
204
+ static sessionLocks = new Map();
205
+
206
+ static async acquireSlot() {
207
+ if (OpenClawClient.runningCount < OpenClawClient.maxConcurrency) {
208
+ OpenClawClient.runningCount++;
209
+ return;
210
+ }
211
+ return new Promise(resolve => OpenClawClient.waitQueue.push(resolve));
212
+ }
213
+
214
+ static releaseSlot() {
215
+ OpenClawClient.runningCount--;
216
+ if (OpenClawClient.waitQueue.length > 0) {
217
+ const next = OpenClawClient.waitQueue.shift();
218
+ OpenClawClient.runningCount++;
219
+ next();
220
+ }
221
+ }
222
+
199
223
  constructor(log) {
200
224
  this.log = log;
201
225
  this.gatewayStarting = false;
@@ -260,6 +284,35 @@ class OpenClawClient {
260
284
 
261
285
  async chatViaCLI(message, fromUser) {
262
286
  const sessionId = `clawmessenger-${fromUser}`;
287
+
288
+ // 1. Session 级串行锁:同一用户的消息排队执行,避免多个进程竞争同一 session 文件
289
+ const previousLock = OpenClawClient.sessionLocks.get(sessionId);
290
+ let resolveLock;
291
+ const currentLock = new Promise(r => { resolveLock = r; });
292
+ OpenClawClient.sessionLocks.set(sessionId, currentLock);
293
+ if (previousLock) {
294
+ this.log?.info(`[OpenClawClient] session ${sessionId} 正在处理中,排队等待...`);
295
+ await previousLock;
296
+ }
297
+
298
+ // 2. 全局并发槽位限制:所有实例共享,防止服务器资源耗尽
299
+ await OpenClawClient.acquireSlot();
300
+ this.log?.info(`[OpenClawClient] 获得执行槽位 (当前运行: ${OpenClawClient.runningCount}/${OpenClawClient.maxConcurrency})`);
301
+
302
+ try {
303
+ return await this._runAgentCLI(message, fromUser, sessionId);
304
+ } finally {
305
+ OpenClawClient.releaseSlot();
306
+ this.log?.info(`[OpenClawClient] 释放执行槽位 (当前运行: ${OpenClawClient.runningCount}/${OpenClawClient.maxConcurrency})`);
307
+ // 释放 session 锁
308
+ resolveLock();
309
+ if (OpenClawClient.sessionLocks.get(sessionId) === currentLock) {
310
+ OpenClawClient.sessionLocks.delete(sessionId);
311
+ }
312
+ }
313
+ }
314
+
315
+ _runAgentCLI(message, fromUser, sessionId) {
263
316
  const escapedMessage = message
264
317
  .replace(/\\/g, '\\\\')
265
318
  .replace(/"/g, '\\"')