whatap 2.0.5 → 2.0.6-canary.0

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.
@@ -38,7 +38,21 @@
38
38
  "Bash(git add *)",
39
39
  "Bash(git commit *)",
40
40
  "Bash(git fetch *)",
41
- "Bash(git push *)"
41
+ "Bash(git push *)",
42
+ "Bash(node --check /Users/seunghunlee/agent_workspace/nodejs_agent/lib/core/agent.js)",
43
+ "Bash(git -C /Users/seunghunlee/agent_workspace/nodejs_agent branch -a)",
44
+ "Bash(git -C /Users/seunghunlee/agent_workspace/nodejs_agent log --all --oneline -- test)",
45
+ "Bash(node *)",
46
+ "Bash(git *)",
47
+ "Read(//Users/seunghunlee/workspace/go_sample/node_modules/whatap/lib/core/**)",
48
+ "Read(//Users/seunghunlee/workspace/go_sample/**)",
49
+ "Bash(rm -f agent-cfd56737.pid agent-cfd56737.lock whatap_nodejs.pid)",
50
+ "Bash(pkill -f whatap_nodejs)",
51
+ "Bash(xargs kill -9)",
52
+ "Bash(kill 34859)",
53
+ "Bash(cp node_modules/whatap/lib/core/agent.js node_modules/whatap/lib/core/agent.js.2.0.5.bak)",
54
+ "Bash(cp /Users/seunghunlee/agent_workspace/nodejs_agent/lib/core/agent.js node_modules/whatap/lib/core/agent.js)",
55
+ "Bash(ls -la agent-*)"
42
56
  ]
43
57
  }
44
58
  }
package/lib/core/agent.js CHANGED
@@ -936,6 +936,52 @@ NodeAgent.prototype.restartGoAgent = function(opts = {}) {
936
936
  return true;
937
937
  };
938
938
 
939
+ // 기동용 lock 파일이 stale인지 판정
940
+ // lock은 spawn 중 몇 초만 존재해야 정상이므로, 소유 프로세스가 죽었거나
941
+ // 생성 후 60초가 지났으면 stale로 간주한다 (pid 재사용 대비 mtime 안전망)
942
+ NodeAgent.prototype.isStaleLockFile = function(lockFile) {
943
+ let lockPid = null;
944
+ try {
945
+ const stat = fs.statSync(lockFile);
946
+ if (Date.now() - stat.mtime.getTime() > 60000) return true;
947
+ lockPid = parseInt(fs.readFileSync(lockFile, 'utf8').trim(), 10);
948
+ } catch (e) {
949
+ return true;
950
+ }
951
+ // 내용이 비어있거나 파싱 불가: 다른 프로세스가 wx로 생성 직후 pid를 쓰기 전 순간일 수 있음
952
+ // (PM2 cluster 동시 부팅에서 발생 가능) → mtime이 신선한 동안은 기동 중으로 간주,
953
+ // 진짜 깨진 파일이면 60초 후 위의 mtime 규칙으로 stale 처리됨
954
+ if (!lockPid) return false;
955
+ try {
956
+ process.kill(lockPid, 0);
957
+ return false;
958
+ } catch (e) {
959
+ // EPERM: 프로세스는 살아있으나 권한 없음 -> stale 아님
960
+ return e.code !== 'EPERM';
961
+ }
962
+ };
963
+
964
+ // 기동용 lock 획득 (O_EXCL로 원자적 생성, stale lock은 제거 후 1회 재시도)
965
+ NodeAgent.prototype.acquireStartLock = function(lockFile) {
966
+ for (let attempt = 0; attempt < 2; attempt++) {
967
+ try {
968
+ fs.writeFileSync(lockFile, process.pid.toString(), { flag: 'wx' });
969
+ return true;
970
+ } catch (e) {
971
+ if (e.code !== 'EEXIST') {
972
+ Logger.printError("WHATAP-033", "Error acquiring lock", e, false);
973
+ return false;
974
+ }
975
+ if (!this.isStaleLockFile(lockFile)) {
976
+ return false;
977
+ }
978
+ Logger.print("WHATAP-225", `Stale lock file detected (${lockFile}), removing and retrying...`, false);
979
+ try { fs.unlinkSync(lockFile); } catch (unlinkErr) {}
980
+ }
981
+ }
982
+ return false;
983
+ };
984
+
939
985
  // startGoAgent with improved PID handling
940
986
  NodeAgent.prototype.startGoAgent = function(opts = {}) {
941
987
  const self = this;
@@ -976,48 +1022,23 @@ NodeAgent.prototype.startGoAgent = function(opts = {}) {
976
1022
  Logger.printError("WHATAP-029", "Error checking shared lock file", e, false);
977
1023
  }
978
1024
 
979
- // 3. PM2 cluster 모드에서는 번째 인스턴스만 에이전트 시작
980
- if (isPM2Cluster) {
981
- // 잠금 파일로 동시 실행 방지
982
- let lockAcquired = false;
983
- try {
984
- if (!fs.existsSync(sharedLockFile)) {
985
- fs.writeFileSync(sharedLockFile, process.pid.toString());
986
- lockAcquired = true;
987
- Logger.print("WHATAP-030",
988
- `PM2 cluster mode: Instance ${process.env.pm_id} will start shared agent`,
989
- false);
990
- } else {
991
- // 다른 인스턴스가 이미 에이전트를 시작하는 중
992
- Logger.print("WHATAP-031",
993
- `PM2 cluster mode: Instance ${process.env.pm_id} detected another instance starting the agent, will use shared agent`,
994
- false);
995
- return;
996
- }
997
- } catch (e) {
998
- Logger.printError("WHATAP-032", "Error acquiring lock in PM2 cluster mode", e, false);
999
- return;
1000
- }
1001
-
1002
- if (!lockAcquired) {
1003
- return;
1004
- }
1005
- } else {
1006
- // 일반 모드에서는 기존 로직 사용
1007
- let lockAcquired = false;
1008
- try {
1009
- if (!fs.existsSync(sharedLockFile)) {
1010
- fs.writeFileSync(sharedLockFile, process.pid.toString());
1011
- lockAcquired = true;
1012
- }
1013
- } catch (e) {
1014
- Logger.printError("WHATAP-033", "Error acquiring lock", e, false);
1015
- }
1016
-
1017
- if (!lockAcquired) {
1025
+ // 3. 잠금 파일로 동시 실행 방지 (stale lock은 자동 제거 후 재시도)
1026
+ if (!this.acquireStartLock(sharedLockFile)) {
1027
+ if (isPM2Cluster) {
1028
+ // 다른 인스턴스가 이미 에이전트를 시작하는 중
1029
+ Logger.print("WHATAP-031",
1030
+ `PM2 cluster mode: Instance ${process.env.pm_id} detected another instance starting the agent, will use shared agent`,
1031
+ false);
1032
+ } else {
1018
1033
  Logger.print("WHATAP-034", "Another process is starting the agent, waiting...", false);
1019
- return;
1020
1034
  }
1035
+ return;
1036
+ }
1037
+
1038
+ if (isPM2Cluster) {
1039
+ Logger.print("WHATAP-030",
1040
+ `PM2 cluster mode: Instance ${process.env.pm_id} will start shared agent`,
1041
+ false);
1021
1042
  }
1022
1043
 
1023
1044
  // 기존 whatap_nodejs.pid 파일 처리 (호환성 유지)
@@ -1206,8 +1227,8 @@ NodeAgent.prototype.startGoAgent = function(opts = {}) {
1206
1227
  Logger.print("WHATAP-040", `PID ${actualPid} written to PID files`, false);
1207
1228
 
1208
1229
  // Lock 파일 해제 (spawn 완료 후 안전하게 삭제)
1230
+ // 이 lock은 proper-lockfile이 아닌 writeFileSync로 생성한 파일이므로 unlink만 수행
1209
1231
  try {
1210
- properLock.unlockSync(sharedLockFile);
1211
1232
  fs.unlinkSync(sharedLockFile);
1212
1233
  Logger.print("WHATAP-041", "Lock file released after spawn", false);
1213
1234
  } catch (e) {}
@@ -1278,10 +1299,7 @@ NodeAgent.prototype.startGoAgent = function(opts = {}) {
1278
1299
  } catch (e) {
1279
1300
  Logger.printError("WHATAP-048", "Error starting agent", e, false);
1280
1301
  // 에러 발생 시 파일 정리
1281
- try {
1282
- properLock.unlockSync(sharedLockFile);
1283
- fs.unlinkSync(sharedLockFile);
1284
- } catch (unlockErr) {}
1302
+ try { fs.unlinkSync(sharedLockFile); } catch (unlockErr) {}
1285
1303
  try { fs.unlinkSync(sharedPidFile); } catch (pidErr) {}
1286
1304
  }
1287
1305
  };
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "whatap",
3
3
  "homepage": "http://www.whatap.io",
4
- "version": "2.0.5",
5
- "releaseDate": "20260709",
4
+ "version": "2.0.6-canary.0",
5
+ "releaseDate": "20260713",
6
6
  "description": "Monitoring and Profiling Service",
7
7
  "main": "index.js",
8
8
  "scripts": {},