echoapi-cron-scheduler-batch 1.0.2 → 1.0.4

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.
Files changed (2) hide show
  1. package/index.js +61 -47
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -42,7 +42,6 @@ class CronScheduler {
42
42
  is_cancel INTEGER DEFAULT 0,
43
43
  api_token TEXT,
44
44
  project_id TEXT,
45
- user_uid TEXT, -- 新增:存储用户UID
46
45
  cases TEXT, -- 存储 runners 数组 JSON
47
46
  create_dtime INTEGER
48
47
  )
@@ -168,7 +167,6 @@ class CronScheduler {
168
167
  job_id: record.job_info.job_id,
169
168
  report_name: record.job_info.name,
170
169
  project_id: record.job_info.project_id,
171
- user_uid: record.job_info.user_uid, // 放入最终报文
172
170
  execution_id: executionId,
173
171
  start_at: this.formatTimeToISO(record.job_info.start_time),
174
172
  end_at: this.formatTimeToISO(endTime),
@@ -295,22 +293,21 @@ class CronScheduler {
295
293
  * 创建或更新任务
296
294
  */
297
295
  createJob(payload) {
298
- const { job_id, name, frequency, api_token, project_id, user_uid, runners } = payload;
296
+ const { job_id, name, frequency, api_token, project_id, runners } = payload;
299
297
  const casesJson = JSON.stringify(Array.isArray(runners) ? runners : []);
300
298
  const freqJson = JSON.stringify(frequency);
301
299
 
302
300
  const stmt = this.db.prepare(`
303
- INSERT INTO jobs (job_id, name, frequency, api_token, project_id, cases, create_dtime)
301
+ INSERT INTO jobs (job_id, name, frequency, api_token, project_id, cases, create_dtime)
304
302
  VALUES (?, ?, ?, ?, ?, ?, ?)
305
303
  ON CONFLICT(job_id) DO UPDATE SET
306
304
  name=excluded.name,
307
305
  frequency=excluded.frequency,
308
306
  cases=excluded.cases,
309
307
  api_token=excluded.api_token,
310
- user_uid=excluded.user_uid, -- 更新时也同步 UID
311
308
  is_cancel=0
312
309
  `);
313
- stmt.run(job_id, name, freqJson, api_token, project_id, user_uid || '', casesJson, Date.now());
310
+ stmt.run(job_id, name, freqJson, api_token, project_id, casesJson, Date.now());
314
311
 
315
312
  // 使用增量更新,不再 loadJobs()
316
313
  this.upsertTimer(job_id, name, frequency, { is_cancel: 0 });
@@ -395,7 +392,6 @@ class CronScheduler {
395
392
  job_id: job.job_id,
396
393
  name: job.name,
397
394
  project_id: job.project_id,
398
- user_uid: job.user_uid, // 将 UID 存入内存
399
395
  start_time: Date.now()
400
396
  // 如果数据库有创建人字段,也可以存入:creator: job.creator
401
397
  }
@@ -404,8 +400,10 @@ class CronScheduler {
404
400
  runners.forEach((runner, index) => {
405
401
  // 负载均衡:选取当前存活的 worker
406
402
  const workers = Object.values(cluster.workers).filter(w => w.isConnected());
403
+ console.log(`[Dispatch] Active workers count: ${workers.length}`);
407
404
  const worker = _.sample(workers);
408
405
  if (worker) {
406
+ console.log(`[Dispatch] Sending Unit ${index} to Worker ${worker.process.pid}`);
409
407
  worker.send({
410
408
  action: 'EXECUTE_UNIT',
411
409
  payload: {
@@ -416,6 +414,8 @@ class CronScheduler {
416
414
  unit_index: index
417
415
  }
418
416
  });
417
+ } else {
418
+ console.error(`[Dispatch Error] No active workers available to handle job ${job.job_id}`);
419
419
  }
420
420
  });
421
421
  } catch (e) {
@@ -428,50 +428,64 @@ class CronScheduler {
428
428
  // ==========================================
429
429
 
430
430
  _startWorker() {
431
- const { run: runner } = require('runner-runtime');
432
- const net = require('net');
433
-
434
- process.on('message', async (msg) => {
435
- if (msg.action === 'EXECUTE_UNIT') {
436
- const { executionId, api_token, test_events, option } = msg.payload;
437
- const socketPath = path.join(os.tmpdir(), `echoapi_${uuidv4()}.sock`);
438
-
439
- const server = net.createServer((socket) => {
440
- socket.on('data', async (stream) => {
441
- try {
442
- const info = JSON.parse(stream.toString());
443
- const { action, data } = info;
444
- await this._handleUnitScript(socket, action, data);
445
- } catch (e) {
446
- socket.write(JSON.stringify({ status: 'error', message: e.message }) + "\n\n");
447
- }
431
+ try {
432
+ console.log(`[Worker ${process.pid}] Starting initialization...`);
433
+ const { run: runner } = require('runner-runtime');
434
+ const net = require('net');
435
+
436
+ process.on('message', async (msg) => {
437
+ if (msg.action === 'EXECUTE_UNIT') {
438
+ const { executionId, api_token, test_events, option } = msg.payload;
439
+ const socketPath = path.join(os.tmpdir(), `echoapi_${uuidv4()}.sock`);
440
+
441
+ const server = net.createServer((socket) => {
442
+ socket.on('data', async (stream) => {
443
+ try {
444
+ const info = JSON.parse(stream.toString());
445
+ const { action, data } = info;
446
+ await this._handleUnitScript(socket, action, data);
447
+ } catch (e) {
448
+ socket.write(JSON.stringify({ status: 'error', message: e.message }) + "\n\n");
449
+ }
450
+ });
448
451
  });
449
- });
450
452
 
451
- server.listen(socketPath, () => {
452
- const finalOptions = _.cloneDeep(option || {});
453
- const base64Pipe = Buffer.from(socketPath).toString('base64');
454
- _.set(finalOptions, 'env.ELECTRON_PIPE', base64Pipe);
455
-
456
- runner(test_events, finalOptions, (res) => {
457
- if (res?.action === 'complete') {
458
- process.send({
459
- action: 'UNIT_COMPLETED',
460
- payload: { executionId, data: res.data, api_token }
461
- });
462
- server.close();
463
- if (fs.existsSync(socketPath)) {
464
- try { fs.unlinkSync(socketPath); } catch (e) { }
453
+ // --- 这里是关键!注册错误监听 ---
454
+ server.on('error', (err) => {
455
+ // 在服务器上看到这个日志,就能定位是权限问题还是路径问题
456
+ console.error(`[Worker Socket Server Error] PID: ${process.pid}`);
457
+ console.error(`[Error Details] Code: ${err.code} | Message: ${err.message}`);
458
+ console.error(`[Attempted Path] ${socketPath}`);
459
+ });
460
+
461
+ server.listen(socketPath, () => {
462
+ const finalOptions = _.cloneDeep(option || {});
463
+ const base64Pipe = Buffer.from(socketPath).toString('base64');
464
+ _.set(finalOptions, 'env.ELECTRON_PIPE', base64Pipe);
465
+
466
+ runner(test_events, finalOptions, (res) => {
467
+ if (res?.action === 'complete') {
468
+ process.send({
469
+ action: 'UNIT_COMPLETED',
470
+ payload: { executionId, data: res.data, api_token }
471
+ });
472
+ server.close();
473
+ if (fs.existsSync(socketPath)) {
474
+ try { fs.unlinkSync(socketPath); } catch (e) { }
475
+ }
465
476
  }
466
- }
477
+ });
467
478
  });
468
- });
469
- }
470
- });
471
- process.on('uncaughtException', (err) => {
472
- console.error('[Worker Fatal Error] 捕获到沙箱崩溃:', err.message);
473
- // 即使崩溃也不要让子进程立即退出,或者让 Master 自动重启它
474
- });
479
+ }
480
+ });
481
+ process.on('uncaughtException', (err) => {
482
+ console.error('[Worker Fatal Error] 捕获到沙箱崩溃:', err.message);
483
+ // 即使崩溃也不要让子进程立即退出,或者让 Master 自动重启它
484
+ });
485
+ } catch (error) {
486
+ console.error(`[Worker ${process.pid}] Critical Boot Error:`, err.stack);
487
+ process.exit(1);
488
+ }
475
489
  }
476
490
 
477
491
  async _handleUnitScript(socket, action, data) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "echoapi-cron-scheduler-batch",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {