@jrosadob/ms-sophia-framework-mysql 0.0.1
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/README.md +101 -0
- package/package.json +105 -0
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Sophia Framework
|
|
2
|
+
|
|
3
|
+
## v47
|
|
4
|
+
Define propiedes dinamicas para el datasource:
|
|
5
|
+
entities, subscribers, synchronize, logging, logger: typeOrmLogger
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## Publish
|
|
10
|
+
+ Actualizar version in package.json
|
|
11
|
+
+ Run `./publish.sh`
|
|
12
|
+
|
|
13
|
+
## CLI
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
$ pnpm install
|
|
17
|
+
$ pnpm add @nestjs/config # Install package
|
|
18
|
+
$ pnpm run start # Development
|
|
19
|
+
$ pnpm run start:dev # Wath mode
|
|
20
|
+
$ pnpm run start:prod # Production mode
|
|
21
|
+
|
|
22
|
+
$ pnpm run test # Unit tests
|
|
23
|
+
$ pnpm run test:e2e # e2e tests
|
|
24
|
+
$ pnpm run test:cov # Coverage test
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Packages
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pnpm add @nestjs/config
|
|
31
|
+
pnpm add @nestjs/swagger
|
|
32
|
+
pnpm add @nestjs/typeorm
|
|
33
|
+
pnpm add axios
|
|
34
|
+
pnpm add class-transformer
|
|
35
|
+
pnpm add class-validator
|
|
36
|
+
pnpm add js
|
|
37
|
+
pnpm add js-yaml
|
|
38
|
+
pnpm add mysql2
|
|
39
|
+
pnpm add nanoid
|
|
40
|
+
pnpm add typeorm
|
|
41
|
+
pnpm add @nestjs/microservices
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## PreHook
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
app.useGlobalInterceptors(new LoggingInterceptor(configService));
|
|
48
|
+
app.useGlobalFilters(new AllExceptionsFilter());
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Idempotencia de Controladores TCP
|
|
52
|
+
Asegurarse de que sea idempotente
|
|
53
|
+
Si es para traer datos no hay problema
|
|
54
|
+
Pero si es para guardar datos, debe usarse una transaccion con una tabla que tiene PK ms-accounts, module-name y method-name.
|
|
55
|
+
Si todo sale bien enviar el ACK.
|
|
56
|
+
Si se detacto duplicado no ejecutar el metodo de negocio, pero enviar el ACK para que RabbitMQ no siga enviando mensajes.
|
|
57
|
+
```TS
|
|
58
|
+
@MessagePattern({ cmd: 'charge' })
|
|
59
|
+
async handleCharge(@Payload() data: any, @Ctx() ctx: RmqContext) {
|
|
60
|
+
const channel = ctx.getChannelRef();
|
|
61
|
+
const msg = ctx.getMessage();
|
|
62
|
+
|
|
63
|
+
const key =
|
|
64
|
+
msg.properties?.headers?.['x-idempotency-key'] ||
|
|
65
|
+
msg.properties?.messageId;
|
|
66
|
+
|
|
67
|
+
if (!key) {
|
|
68
|
+
// Sin clave no hay deduplicación confiable
|
|
69
|
+
// Decide: rechazar o procesar con riesgo
|
|
70
|
+
channel.nack(msg, false, false);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
await this.dataSource.transaction(async (manager) => {
|
|
76
|
+
// 1) Intentar registrar el mensaje
|
|
77
|
+
// Si falla por unique, es duplicado
|
|
78
|
+
await manager.query(
|
|
79
|
+
`INSERT INTO processed_messages (consumer_name, message_key)
|
|
80
|
+
VALUES (?, ?)`,
|
|
81
|
+
['payments-consumer', key],
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
// 2) Lógica de negocio real (solo primera vez)
|
|
85
|
+
await this.paymentService.charge(data, manager);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// 3) Confirmar
|
|
89
|
+
channel.ack(msg);
|
|
90
|
+
} catch (e: any) {
|
|
91
|
+
// Duplicado por unique constraint: confirmar y salir
|
|
92
|
+
if (isDuplicateKeyError(e)) {
|
|
93
|
+
channel.ack(msg);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Error real: reintentar o enviar a DLQ según estrategia
|
|
98
|
+
channel.nack(msg, false, true);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jrosadob/ms-sophia-framework-mysql",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Sophia Framework para microservicios en NestJS",
|
|
5
|
+
"main": "dist/core/index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"peerDependencies": {
|
|
10
|
+
"@nestjs/common": "^11.0.1"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"nest",
|
|
14
|
+
"nestjs",
|
|
15
|
+
"sophia",
|
|
16
|
+
"framework",
|
|
17
|
+
"microservices"
|
|
18
|
+
],
|
|
19
|
+
"author": {
|
|
20
|
+
"name": "Javier A. Rosado Baltazar",
|
|
21
|
+
"email": "jrosadob@hotmail.com"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@nestjs/common": "^11.0.1",
|
|
29
|
+
"@nestjs/config": "^4.0.2",
|
|
30
|
+
"@nestjs/core": "^11.0.1",
|
|
31
|
+
"@nestjs/microservices": "^11.1.27",
|
|
32
|
+
"@nestjs/platform-express": "^11.0.1",
|
|
33
|
+
"@nestjs/swagger": "^11.2.0",
|
|
34
|
+
"@nestjs/typeorm": "^11.0.0",
|
|
35
|
+
"amqp-connection-manager": "^5.0.0",
|
|
36
|
+
"amqplib": "^2.0.1",
|
|
37
|
+
"axios": "^1.12.2",
|
|
38
|
+
"class-transformer": "^0.5.1",
|
|
39
|
+
"class-validator": "^0.14.2",
|
|
40
|
+
"dotenv": "^17.2.3",
|
|
41
|
+
"js": "^0.1.0",
|
|
42
|
+
"js-yaml": "^4.1.0",
|
|
43
|
+
"mysql2": "^3.14.5",
|
|
44
|
+
"nanoid": "^5.1.5",
|
|
45
|
+
"reflect-metadata": "^0.2.2",
|
|
46
|
+
"rxjs": "^7.8.1",
|
|
47
|
+
"typeorm": "^0.3.26"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@eslint/eslintrc": "^3.2.0",
|
|
51
|
+
"@eslint/js": "^9.18.0",
|
|
52
|
+
"@nestjs/cli": "^11.0.0",
|
|
53
|
+
"@nestjs/schematics": "^11.0.0",
|
|
54
|
+
"@nestjs/testing": "^11.0.1",
|
|
55
|
+
"@types/express": "^5.0.0",
|
|
56
|
+
"@types/jest": "^30.0.0",
|
|
57
|
+
"@types/node": "^22.10.7",
|
|
58
|
+
"@types/supertest": "^6.0.2",
|
|
59
|
+
"eslint": "^9.18.0",
|
|
60
|
+
"eslint-config-prettier": "^10.0.1",
|
|
61
|
+
"eslint-plugin-prettier": "^5.2.2",
|
|
62
|
+
"globals": "^16.0.0",
|
|
63
|
+
"jest": "^30.0.0",
|
|
64
|
+
"prettier": "^3.4.2",
|
|
65
|
+
"source-map-support": "^0.5.21",
|
|
66
|
+
"supertest": "^7.0.0",
|
|
67
|
+
"ts-jest": "^29.2.5",
|
|
68
|
+
"ts-loader": "^9.5.2",
|
|
69
|
+
"ts-node": "^10.9.2",
|
|
70
|
+
"tsconfig-paths": "^4.2.0",
|
|
71
|
+
"typescript": "^5.7.3",
|
|
72
|
+
"typescript-eslint": "^8.20.0"
|
|
73
|
+
},
|
|
74
|
+
"jest": {
|
|
75
|
+
"moduleFileExtensions": [
|
|
76
|
+
"js",
|
|
77
|
+
"json",
|
|
78
|
+
"ts"
|
|
79
|
+
],
|
|
80
|
+
"rootDir": "src",
|
|
81
|
+
"testRegex": ".*\\.spec\\.ts$",
|
|
82
|
+
"transform": {
|
|
83
|
+
"^.+\\.(t|j)s$": "ts-jest"
|
|
84
|
+
},
|
|
85
|
+
"collectCoverageFrom": [
|
|
86
|
+
"**/*.(t|j)s"
|
|
87
|
+
],
|
|
88
|
+
"coverageDirectory": "../coverage",
|
|
89
|
+
"testEnvironment": "node"
|
|
90
|
+
},
|
|
91
|
+
"scripts": {
|
|
92
|
+
"build": "nest build",
|
|
93
|
+
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
94
|
+
"start": "nest start",
|
|
95
|
+
"start:dev": "nest start --watch",
|
|
96
|
+
"start:debug": "nest start --debug --watch",
|
|
97
|
+
"start:prod": "node dist/main",
|
|
98
|
+
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
|
99
|
+
"test": "jest",
|
|
100
|
+
"test:watch": "jest --watch",
|
|
101
|
+
"test:cov": "jest --coverage",
|
|
102
|
+
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
|
103
|
+
"test:e2e": "jest --config ./test/jest-e2e.json"
|
|
104
|
+
}
|
|
105
|
+
}
|