style: auto-format code via Prettier [skip ci]

This commit is contained in:
Gitea Actions
2026-02-19 11:28:52 +05:00
parent 0c23aa4c5e
commit f6f4415aeb
2 changed files with 89 additions and 67 deletions

View File

@@ -12,13 +12,13 @@ The PM2 namespace implementation for the flyer-crawler project is now 100% compl
### Key Achievements
| Metric | Value |
|--------|-------|
| **Namespaces Implemented** | 3 (production, test, development) |
| **Workflow Files Updated** | 6 |
| **Config Files Modified** | 3 |
| **Test Coverage** | 89 tests (all passing) |
| **Race Conditions Eliminated** | `pm2 save` isolation complete |
| Metric | Value |
| ------------------------------ | --------------------------------- |
| **Namespaces Implemented** | 3 (production, test, development) |
| **Workflow Files Updated** | 6 |
| **Config Files Modified** | 3 |
| **Test Coverage** | 89 tests (all passing) |
| **Race Conditions Eliminated** | `pm2 save` isolation complete |
---
@@ -40,11 +40,11 @@ Prior to this implementation, the project experienced critical issues with PM2 p
### Namespace Architecture
| Environment | Namespace | Config File | Use Case |
|-------------|-----------|-------------|----------|
| Production | `flyer-crawler-prod` | `ecosystem.config.cjs` | Live production deployment |
| Test | `flyer-crawler-test` | `ecosystem-test.config.cjs` | Staging/test deployment |
| Development | `flyer-crawler-dev` | `ecosystem.dev.config.cjs` | Local development in dev container |
| Environment | Namespace | Config File | Use Case |
| ----------- | -------------------- | --------------------------- | ---------------------------------- |
| Production | `flyer-crawler-prod` | `ecosystem.config.cjs` | Live production deployment |
| Test | `flyer-crawler-test` | `ecosystem-test.config.cjs` | Staging/test deployment |
| Development | `flyer-crawler-dev` | `ecosystem.dev.config.cjs` | Local development in dev container |
### Namespace Definition Pattern
@@ -55,10 +55,10 @@ Each ecosystem config defines its namespace at the module.exports level (not ins
module.exports = {
namespace: 'flyer-crawler-prod',
apps: [
{ name: 'flyer-crawler-api', /* ... */ },
{ name: 'flyer-crawler-worker', /* ... */ },
{ name: 'flyer-crawler-analytics-worker', /* ... */ }
]
{ name: 'flyer-crawler-api' /* ... */ },
{ name: 'flyer-crawler-worker' /* ... */ },
{ name: 'flyer-crawler-analytics-worker' /* ... */ },
],
};
```
@@ -68,22 +68,22 @@ module.exports = {
### Ecosystem Configuration Files
| File | Change |
|------|--------|
| `ecosystem.config.cjs` | Added `namespace: 'flyer-crawler-prod'` at module.exports level |
| File | Change |
| --------------------------- | --------------------------------------------------------------- |
| `ecosystem.config.cjs` | Added `namespace: 'flyer-crawler-prod'` at module.exports level |
| `ecosystem-test.config.cjs` | Added `namespace: 'flyer-crawler-test'` at module.exports level |
| `ecosystem.dev.config.cjs` | Added `namespace: 'flyer-crawler-dev'` at module.exports level |
| `ecosystem.dev.config.cjs` | Added `namespace: 'flyer-crawler-dev'` at module.exports level |
### Workflow Files
| File | Changes |
|------|---------|
| `.gitea/workflows/deploy-to-prod.yml` | Added `--namespace flyer-crawler-prod` to all PM2 commands |
| `.gitea/workflows/deploy-to-test.yml` | Added `--namespace flyer-crawler-test` to all PM2 commands |
| `.gitea/workflows/restart-pm2.yml` | Added `--namespace` flags for both test and production environments |
| `.gitea/workflows/manual-db-restore.yml` | Added `--namespace flyer-crawler-prod` to PM2 stop, save, and startOrReload commands |
| `.gitea/workflows/manual-deploy-major.yml` | Added `--namespace flyer-crawler-prod` to PM2 commands |
| `.gitea/workflows/pm2-diagnostics.yml` | Added namespace-specific sections for both production and test |
| File | Changes |
| ------------------------------------------ | ------------------------------------------------------------------------------------ |
| `.gitea/workflows/deploy-to-prod.yml` | Added `--namespace flyer-crawler-prod` to all PM2 commands |
| `.gitea/workflows/deploy-to-test.yml` | Added `--namespace flyer-crawler-test` to all PM2 commands |
| `.gitea/workflows/restart-pm2.yml` | Added `--namespace` flags for both test and production environments |
| `.gitea/workflows/manual-db-restore.yml` | Added `--namespace flyer-crawler-prod` to PM2 stop, save, and startOrReload commands |
| `.gitea/workflows/manual-deploy-major.yml` | Added `--namespace flyer-crawler-prod` to PM2 commands |
| `.gitea/workflows/pm2-diagnostics.yml` | Added namespace-specific sections for both production and test |
### Session-Specific Modifications (2026-02-18)
@@ -103,16 +103,16 @@ The following files were modified in the final session to ensure complete namesp
### Migration Script
| File | Purpose |
|------|---------|
| File | Purpose |
| ----------------------------------- | ------------------------------------------------------------------------------- |
| `scripts/migrate-pm2-namespaces.sh` | Zero-downtime migration script for transitioning servers to namespace-based PM2 |
### Documentation
| File | Purpose |
|------|---------|
| `docs/adr/0063-pm2-namespace-implementation.md` | Architecture Decision Record documenting the design |
| `CLAUDE.md` | Updated PM2 Namespace Isolation section with usage examples |
| File | Purpose |
| ----------------------------------------------- | ----------------------------------------------------------- |
| `docs/adr/0063-pm2-namespace-implementation.md` | Architecture Decision Record documenting the design |
| `CLAUDE.md` | Updated PM2 Namespace Isolation section with usage examples |
---
@@ -173,6 +173,7 @@ Total: **89 tests** (all passing)
### 1. Race Condition Elimination
Before:
```
Test deploy: pm2 save -> writes to ~/.pm2/dump.pm2
Prod deploy: pm2 save -> overwrites ~/.pm2/dump.pm2
@@ -180,6 +181,7 @@ PM2 daemon restart -> incomplete process list
```
After:
```
Test deploy: pm2 save --namespace flyer-crawler-test -> writes to ~/.pm2/dump-flyer-crawler-test.pm2
Prod deploy: pm2 save --namespace flyer-crawler-prod -> writes to ~/.pm2/dump-flyer-crawler-prod.pm2
@@ -189,6 +191,7 @@ PM2 daemon restart -> both environments fully restored
### 2. Safe Parallel Deployments
Test and production deployments can now run simultaneously without interference. Each namespace operates independently with its own:
- Process list
- Dump file
- Logs (when using namespace filter)
@@ -196,16 +199,18 @@ Test and production deployments can now run simultaneously without interference.
### 3. Simplified Commands
Before (with filtering logic):
```javascript
// Complex inline JavaScript filtering
const list = JSON.parse(execSync('pm2 jlist').toString());
const prodProcesses = list.filter(p =>
['flyer-crawler-api', 'flyer-crawler-worker', 'flyer-crawler-analytics-worker'].includes(p.name)
const prodProcesses = list.filter((p) =>
['flyer-crawler-api', 'flyer-crawler-worker', 'flyer-crawler-analytics-worker'].includes(p.name),
);
prodProcesses.forEach(p => execSync(`pm2 delete ${p.pm_id}`));
prodProcesses.forEach((p) => execSync(`pm2 delete ${p.pm_id}`));
```
After (simple namespace flag):
```bash
pm2 delete all --namespace flyer-crawler-prod
```
@@ -347,13 +352,13 @@ pm2 list # Should show processes organized by namespace
## Related Documentation
| Document | Purpose |
|----------|---------|
| [ADR-063: PM2 Namespace Implementation](../adr/0063-pm2-namespace-implementation.md) | Architecture decision record |
| [ADR-061: PM2 Process Isolation Safeguards](../adr/0061-pm2-process-isolation-safeguards.md) | Prior safeguards (still active) |
| [CLAUDE.md](../../CLAUDE.md) | PM2 Namespace Isolation section (lines 52-169) |
| [PM2 Incident Response Runbook](./PM2-INCIDENT-RESPONSE.md) | Emergency procedures |
| [Incident Report 2026-02-17](./INCIDENT-2026-02-17-PM2-PROCESS-KILL.md) | Root cause analysis |
| Document | Purpose |
| -------------------------------------------------------------------------------------------- | ---------------------------------------------- |
| [ADR-063: PM2 Namespace Implementation](../adr/0063-pm2-namespace-implementation.md) | Architecture decision record |
| [ADR-061: PM2 Process Isolation Safeguards](../adr/0061-pm2-process-isolation-safeguards.md) | Prior safeguards (still active) |
| [CLAUDE.md](../../CLAUDE.md) | PM2 Namespace Isolation section (lines 52-169) |
| [PM2 Incident Response Runbook](./PM2-INCIDENT-RESPONSE.md) | Emergency procedures |
| [Incident Report 2026-02-17](./INCIDENT-2026-02-17-PM2-PROCESS-KILL.md) | Root cause analysis |
---
@@ -373,16 +378,16 @@ pm2 list # Should show processes organized by namespace
## Appendix: Command Quick Reference
| Action | Production | Test |
|--------|------------|------|
| Start | `pm2 start ecosystem.config.cjs --namespace flyer-crawler-prod` | `pm2 start ecosystem-test.config.cjs --namespace flyer-crawler-test` |
| Stop all | `pm2 stop all --namespace flyer-crawler-prod` | `pm2 stop all --namespace flyer-crawler-test` |
| Restart all | `pm2 restart all --namespace flyer-crawler-prod` | `pm2 restart all --namespace flyer-crawler-test` |
| Delete all | `pm2 delete all --namespace flyer-crawler-prod` | `pm2 delete all --namespace flyer-crawler-test` |
| List | `pm2 list --namespace flyer-crawler-prod` | `pm2 list --namespace flyer-crawler-test` |
| Logs | `pm2 logs --namespace flyer-crawler-prod` | `pm2 logs --namespace flyer-crawler-test` |
| Save | `pm2 save --namespace flyer-crawler-prod` | `pm2 save --namespace flyer-crawler-test` |
| Describe | `pm2 describe flyer-crawler-api --namespace flyer-crawler-prod` | `pm2 describe flyer-crawler-api-test --namespace flyer-crawler-test` |
| Action | Production | Test |
| ----------- | --------------------------------------------------------------- | -------------------------------------------------------------------- |
| Start | `pm2 start ecosystem.config.cjs --namespace flyer-crawler-prod` | `pm2 start ecosystem-test.config.cjs --namespace flyer-crawler-test` |
| Stop all | `pm2 stop all --namespace flyer-crawler-prod` | `pm2 stop all --namespace flyer-crawler-test` |
| Restart all | `pm2 restart all --namespace flyer-crawler-prod` | `pm2 restart all --namespace flyer-crawler-test` |
| Delete all | `pm2 delete all --namespace flyer-crawler-prod` | `pm2 delete all --namespace flyer-crawler-test` |
| List | `pm2 list --namespace flyer-crawler-prod` | `pm2 list --namespace flyer-crawler-test` |
| Logs | `pm2 logs --namespace flyer-crawler-prod` | `pm2 logs --namespace flyer-crawler-test` |
| Save | `pm2 save --namespace flyer-crawler-prod` | `pm2 save --namespace flyer-crawler-test` |
| Describe | `pm2 describe flyer-crawler-api --namespace flyer-crawler-prod` | `pm2 describe flyer-crawler-api-test --namespace flyer-crawler-test` |
---

View File

@@ -89,8 +89,8 @@ describe('PM2 Namespace Implementation', () => {
// Extract just the module.exports block to avoid matching 'apps:' in comments
const exportBlock = content.slice(content.indexOf('module.exports'));
const namespaceInExport = exportBlock.indexOf("namespace:");
const appsInExport = exportBlock.indexOf("apps:");
const namespaceInExport = exportBlock.indexOf('namespace:');
const appsInExport = exportBlock.indexOf('apps:');
expect(namespaceInExport).toBeGreaterThan(-1);
expect(appsInExport).toBeGreaterThan(-1);
@@ -136,8 +136,8 @@ describe('PM2 Namespace Implementation', () => {
// Extract just the module.exports block to avoid matching 'apps:' in comments
const exportBlock = content.slice(content.indexOf('module.exports'));
const namespaceInExport = exportBlock.indexOf("namespace:");
const appsInExport = exportBlock.indexOf("apps:");
const namespaceInExport = exportBlock.indexOf('namespace:');
const appsInExport = exportBlock.indexOf('apps:');
expect(namespaceInExport).toBeGreaterThan(-1);
expect(appsInExport).toBeGreaterThan(-1);
@@ -183,8 +183,8 @@ describe('PM2 Namespace Implementation', () => {
// Extract just the module.exports block to avoid matching 'apps:' in comments
const exportBlock = content.slice(content.indexOf('module.exports'));
const namespaceInExport = exportBlock.indexOf("namespace:");
const appsInExport = exportBlock.indexOf("apps:");
const namespaceInExport = exportBlock.indexOf('namespace:');
const appsInExport = exportBlock.indexOf('apps:');
expect(namespaceInExport).toBeGreaterThan(-1);
expect(appsInExport).toBeGreaterThan(-1);
@@ -293,10 +293,17 @@ describe('PM2 Namespace Implementation', () => {
const problematicLines = lines.filter((line) => {
const trimmed = line.trim();
// Skip comments, echo statements (log messages), and inline JS exec/execSync calls
if (trimmed.startsWith('#') || trimmed.startsWith('echo ') || trimmed.includes('exec(') || trimmed.includes('execSync(')) return false;
if (
trimmed.startsWith('#') ||
trimmed.startsWith('echo ') ||
trimmed.includes('exec(') ||
trimmed.includes('execSync(')
)
return false;
// Check for pm2 commands that should have namespace
const hasPm2Command = /pm2\s+(save|restart|stop|delete|list|jlist|describe|logs|env|ps)(\s|$)/.test(trimmed);
const hasPm2Command =
/pm2\s+(save|restart|stop|delete|list|jlist|describe|logs|env|ps)(\s|$)/.test(trimmed);
if (!hasPm2Command) return false;
// If it has a pm2 command, it should include --namespace
@@ -393,7 +400,7 @@ describe('PM2 Namespace Implementation', () => {
it('should support environment selection input', () => {
expect(workflow).toContain('environment:');
expect(workflow).toContain("type: choice");
expect(workflow).toContain('type: choice');
expect(workflow).toContain('test');
expect(workflow).toContain('production');
expect(workflow).toContain('both');
@@ -720,8 +727,12 @@ describe('PM2 Namespace Implementation', () => {
it('should show correct namespace examples', () => {
// Check for correct usage examples
expect(claudeMdContent).toContain('pm2 start ecosystem.config.cjs --namespace flyer-crawler-prod');
expect(claudeMdContent).toContain('pm2 start ecosystem-test.config.cjs --namespace flyer-crawler-test');
expect(claudeMdContent).toContain(
'pm2 start ecosystem.config.cjs --namespace flyer-crawler-prod',
);
expect(claudeMdContent).toContain(
'pm2 start ecosystem-test.config.cjs --namespace flyer-crawler-test',
);
});
it('should warn against using pm2 commands without namespace', () => {
@@ -816,14 +827,20 @@ describe('PM2 Namespace Implementation', () => {
// Count PM2 commands vs PM2 commands with namespace
// In properly migrated workflows, most PM2 commands should have namespace
const testPm2Commands = testWorkflow.match(/pm2\s+(list|jlist|save|stop|start|delete|restart|logs|describe|env|startOrReload)/g) || [];
const testPm2Commands =
testWorkflow.match(
/pm2\s+(list|jlist|save|stop|start|delete|restart|logs|describe|env|startOrReload)/g,
) || [];
const testNamespacedCommands = testWorkflow.match(/pm2\s+\w+.*--namespace/g) || [];
// Most PM2 commands should have namespace (allow some slack for inline JS)
const testRatio = testNamespacedCommands.length / testPm2Commands.length;
expect(testRatio).toBeGreaterThan(0.5); // At least 50% should have namespace
const prodPm2Commands = prodWorkflow.match(/pm2\s+(list|jlist|save|stop|start|delete|restart|logs|describe|env|startOrReload)/g) || [];
const prodPm2Commands =
prodWorkflow.match(
/pm2\s+(list|jlist|save|stop|start|delete|restart|logs|describe|env|startOrReload)/g,
) || [];
const prodNamespacedCommands = prodWorkflow.match(/pm2\s+\w+.*--namespace/g) || [];
const prodRatio = prodNamespacedCommands.length / prodPm2Commands.length;