Docs y prueba de concepto de colas por empresa
This commit is contained in:
17
README.md
17
README.md
@@ -3,3 +3,20 @@
|
|||||||
Monorepo de servicios / workers para centralizar los procesos de las SIM con sus subscripciones
|
Monorepo de servicios / workers para centralizar los procesos de las SIM con sus subscripciones
|
||||||
|
|
||||||
[[./imgs/diagrama-servicios-sim.png]]
|
[[./imgs/diagrama-servicios-sim.png]]
|
||||||
|
|
||||||
|
El objetivo es que al lanzar peticiones REST a la parte visible, que se
|
||||||
|
comprueben y se manden al broker para que los servicios de las compañías
|
||||||
|
los puedan consumir.
|
||||||
|
|
||||||
|
La idea es que las peticiones de activación, pausa, etc. no necesiten
|
||||||
|
tener una compañía especificada.
|
||||||
|
|
||||||
|
## Decisiones pendientes
|
||||||
|
|
||||||
|
- [ ] La capa worker según acción y la de operaciones de proveedores
|
||||||
|
se podrían unir en una sola con un enrutamiento por acción y compañía
|
||||||
|
pasando de tener claves `sim.[acción]` a `sim.[compañia].[acción]`.
|
||||||
|
- [ ] La estructura de RMQ se genera por medio del JSON, igual habría que
|
||||||
|
definir cada cola en el worker que la consuma para poder añadir
|
||||||
|
workers sin parar el RMQ.
|
||||||
|
- [ ] Versionado de la API.
|
||||||
|
|||||||
16
docs/sim-api/Activate.bru
Normal file
16
docs/sim-api/Activate.bru
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
meta {
|
||||||
|
name: Activate
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: {{baseurl}}/sim/activate
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
16
docs/sim-api/Cancel.bru
Normal file
16
docs/sim-api/Cancel.bru
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
meta {
|
||||||
|
name: Cancel
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: {{baseurl}}/sim/cancel
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
16
docs/sim-api/Pause.bru
Normal file
16
docs/sim-api/Pause.bru
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
meta {
|
||||||
|
name: Pause
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: {{baseurl}}/sim/pause
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
16
docs/sim-api/Preactivate.bru
Normal file
16
docs/sim-api/Preactivate.bru
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
meta {
|
||||||
|
name: Preactivate
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: {{baseurl}}/sim/preactivate
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
9
docs/sim-api/bruno.json
Normal file
9
docs/sim-api/bruno.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"version": "1",
|
||||||
|
"name": "sim-api",
|
||||||
|
"type": "collection",
|
||||||
|
"ignore": [
|
||||||
|
"node_modules",
|
||||||
|
".git"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
docs/sim-api/environments/local.bru
Normal file
3
docs/sim-api/environments/local.bru
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
vars {
|
||||||
|
baseurl: http://locahost
|
||||||
|
}
|
||||||
@@ -8,4 +8,5 @@ export interface EventBus {
|
|||||||
|
|
||||||
consume(queue: string, callback: (msg: ConsumeMessage | null) => void): void;
|
consume(queue: string, callback: (msg: ConsumeMessage | null) => void): void;
|
||||||
ack(msg: ConsumeMessage): void;
|
ack(msg: ConsumeMessage): void;
|
||||||
|
nack(msg: ConsumeMessage): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ export class RabbitMQEventBus implements EventBus {
|
|||||||
return this.channel.ack(msg)
|
return this.channel.ack(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nack(msg: ConsumeMessage) {
|
||||||
|
if (this.channel == undefined) throw new Error("[RMQ] Canal no iniciallizado");
|
||||||
|
return this.channel.nack(msg)
|
||||||
|
}
|
||||||
|
|
||||||
connection?: ChannelModel
|
connection?: ChannelModel
|
||||||
channel?: ConfirmChannel
|
channel?: ConfirmChannel
|
||||||
connected: Boolean = false
|
connected: Boolean = false
|
||||||
|
|||||||
22
packages/sim-consumidor-nos/.env
Normal file
22
packages/sim-consumidor-nos/.env
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
PORT=3000
|
||||||
|
RABBITMQ_USER=guest
|
||||||
|
RABBITMQ_PASSWORD=guest
|
||||||
|
|
||||||
|
ENVIORMENT=development
|
||||||
|
|
||||||
|
RABBITMQ_HOST=rabbitmq-sim-broker
|
||||||
|
#RABBITMQ_HOST=localhost
|
||||||
|
RABBITMQ_PORT=5672
|
||||||
|
RABBITMQ_USER=guest
|
||||||
|
RABBITMQ_PASSWORD=guest
|
||||||
|
RABBITMQ_SECURE=false
|
||||||
|
RABBITMQ_VHOST=sim-vhost
|
||||||
|
|
||||||
|
# Hay cosas que unificar de varios servicios
|
||||||
|
POSTGRES_DB=postgres
|
||||||
|
POSTGRES_DATABASE=postres
|
||||||
|
POSTGRES_HOST=postgresql-sim-1
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
DEV_POSTGRES_PORT=5432
|
||||||
|
POSTGRES_USER=postgres
|
||||||
|
POSTGRES_PASSWORD=1234
|
||||||
65
packages/sim-consumidor-nos/aplication/SimNOS.controller.ts
Normal file
65
packages/sim-consumidor-nos/aplication/SimNOS.controller.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { EventBus } from "#shared/domain/EventBus.port";
|
||||||
|
import { ConsumeMessage } from "amqplib";
|
||||||
|
|
||||||
|
export class SimNosController {
|
||||||
|
private eventBus: EventBus;
|
||||||
|
private activationUseCases: any;
|
||||||
|
|
||||||
|
private routes = new Map<string, () => void>([
|
||||||
|
["activate", async () => { console.log("caso de uso activate") }],
|
||||||
|
["pause", async () => { console.log("caso de uso pause") }],
|
||||||
|
["cancel", async () => { console.log("caso de uso cancel") }],
|
||||||
|
])
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
eventBus: EventBus
|
||||||
|
) {
|
||||||
|
this.eventBus = eventBus
|
||||||
|
|
||||||
|
// No se si hay un sistema mejor
|
||||||
|
// convertor en const () => {} para conservar el contexto??
|
||||||
|
this.recibeMsg = this.recibeMsg.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async recibeMsg(msg: ConsumeMessage | null) {
|
||||||
|
if (!this.validateActivationMsg(msg)) {
|
||||||
|
throw new Error("Error consumiendo el mensaje no es valido")
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = msg!
|
||||||
|
|
||||||
|
const msgParsed = JSON.parse(String(msg.content))
|
||||||
|
const msgKey = msg.fields.routingKey.split(".")
|
||||||
|
const accion = msgKey[2]
|
||||||
|
|
||||||
|
if (accion == undefined) {
|
||||||
|
console.error("La routingKey es incorrecta: " + accion)
|
||||||
|
this.eventBus.nack(msg)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.routes.get(accion) == undefined) {
|
||||||
|
console.error("No hay una ruta definida para la accion")
|
||||||
|
this.eventBus.nack(msg)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.routes.get(accion)!()
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Error procesando el mensaje")
|
||||||
|
this.eventBus.nack(msg)
|
||||||
|
} finally {
|
||||||
|
this.eventBus.ack(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO:
|
||||||
|
* - Loguear motivos de la no validacion
|
||||||
|
*/
|
||||||
|
private validateActivationMsg(msg: ConsumeMessage | null) {
|
||||||
|
if (msg == undefined) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
packages/sim-consumidor-nos/config/env/index.ts
vendored
Normal file
22
packages/sim-consumidor-nos/config/env/index.ts
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { loadEnvFile } from "node:process";
|
||||||
|
loadEnvFile("../../.env")
|
||||||
|
|
||||||
|
export const env = {
|
||||||
|
ENVIRONMENT: process.env.ENVIORMENT,
|
||||||
|
POSTGRES_USER: process.env.POSTGRES_USER,
|
||||||
|
POSTGRES_PASSWORD: process.env.POSTGRES_PASSWORD,
|
||||||
|
POSTGRES_PORT: process.env.POSTGRES_PORT,
|
||||||
|
POSTGRES_HOST: process.env.POSTGRES_HOST,
|
||||||
|
POSTGRES_DATABASE: process.env.POSTGRES_DATABASE,
|
||||||
|
RABBITMQ_HOST: String(process.env.RABBITMQ_HOST ?? "localhost"),
|
||||||
|
RABBITMQ_USER: String(process.env.RABBITMQ_USER ?? "guest"),
|
||||||
|
RABBITMQ_PASSWORD: String(process.env.RABBITMQ_PASSWORD ?? "guest"),
|
||||||
|
RABBITMQ_EXCHANGE: String(process.env.RABBITMQ_EXCHANGE ?? "/"),
|
||||||
|
RABBITMQ_PORT: parseInt(process.env.RABBITMQ_PORT ?? "5672"),
|
||||||
|
RABBITMQ_MODULENAME: process.env.MODULENAME,
|
||||||
|
RABBITMQ_TTL: process.env.RABBITMQ_TTL,
|
||||||
|
RABBITMQ_SECURE: process.env.RABBITMQ_SECURE,
|
||||||
|
RABBITMQ_RETRY_INTERVAL: process.env.RABBITMQ_INTERVAL,
|
||||||
|
RABBITMQ_VHOST: String(process.env.RABBITMQ_VHOST),
|
||||||
|
};
|
||||||
|
|
||||||
36
packages/sim-consumidor-nos/config/eventBusConfig.ts
Normal file
36
packages/sim-consumidor-nos/config/eventBusConfig.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { RabbitMQEventBus, RMQConnectionParams } from "#shared/infrastructure/RabbitMQEventBus"
|
||||||
|
import { env } from "./env"
|
||||||
|
|
||||||
|
const rmqUser = env.RABBITMQ_USER
|
||||||
|
const rmqPass = env.RABBITMQ_PASSWORD
|
||||||
|
const rmqHost = env.RABBITMQ_HOST
|
||||||
|
const rmqPort = Number(env.RABBITMQ_PORT)
|
||||||
|
const rmqSecure = false
|
||||||
|
const rmqVhost = env.RABBITMQ_VHOST
|
||||||
|
|
||||||
|
export const rmqConnOptions = <RMQConnectionParams>{
|
||||||
|
username: rmqUser,
|
||||||
|
password: rmqPass,
|
||||||
|
vhost: rmqVhost,
|
||||||
|
hostname: rmqHost,
|
||||||
|
port: rmqPort,
|
||||||
|
secure: rmqSecure,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const rabbitmqEventBus = new RabbitMQEventBus({
|
||||||
|
connectionParams: rmqConnOptions
|
||||||
|
})
|
||||||
|
|
||||||
|
export async function startRMQClient() {
|
||||||
|
await rabbitmqEventBus.connect()
|
||||||
|
|
||||||
|
// Bindings especificos, deberia meterlos en la clase
|
||||||
|
try {
|
||||||
|
rabbitmqEventBus.channel?.assertQueue("sim.nos")
|
||||||
|
} catch {
|
||||||
|
console.log("[i] Cola de sims de nos creada")
|
||||||
|
rabbitmqEventBus.channel?.bindQueue("sim.nos", "sim.exchange", "sim.nos.*")
|
||||||
|
}
|
||||||
|
|
||||||
|
return rabbitmqEventBus
|
||||||
|
}
|
||||||
22
packages/sim-consumidor-nos/index.ts
Normal file
22
packages/sim-consumidor-nos/index.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
import { startRMQClient } from "#config/eventBusConfig"
|
||||||
|
import { SimNosController } from "aplication/SimNOS.controller"
|
||||||
|
|
||||||
|
async function startWorker() {
|
||||||
|
const rmqClient = await startRMQClient()
|
||||||
|
const simController = new SimNosController(
|
||||||
|
rmqClient
|
||||||
|
)
|
||||||
|
|
||||||
|
rmqClient.consume("sim.nos", simController.recibeMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
startWorker()
|
||||||
|
.then(e => {
|
||||||
|
console.log("[o] Worker de SIM de NOS iniciado")
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.log("[x] Error iniciando worker de SIM de NOS")
|
||||||
|
})
|
||||||
|
|
||||||
|
export default {}
|
||||||
32
packages/sim-consumidor-nos/package.json
Normal file
32
packages/sim-consumidor-nos/package.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "sim-consumidor-nos",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "consumidor generico de eventos de NOS",
|
||||||
|
"main": "index.ts",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"dev": "tsx watch index.ts "
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"packageManager": "yarn@4.12.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@tsconfig/node22": "*",
|
||||||
|
"amqplib": "^0.10.9",
|
||||||
|
"cors": "*",
|
||||||
|
"dotenv": "*",
|
||||||
|
"express": "*",
|
||||||
|
"typescript": "*"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/amqplib": "^0.10.8",
|
||||||
|
"@types/cors": "*",
|
||||||
|
"@types/express": "*",
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/supertest": "*",
|
||||||
|
"prettier": "*",
|
||||||
|
"supertest": "*",
|
||||||
|
"tsx": "*",
|
||||||
|
"vitest": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
37
packages/sim-consumidor-nos/tsconfig.json
Normal file
37
packages/sim-consumidor-nos/tsconfig.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../dist/sim-consumidor-nos",
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"#config/*": [
|
||||||
|
"config/*"
|
||||||
|
],
|
||||||
|
"#adapters/*": [
|
||||||
|
"adapters/*"
|
||||||
|
],
|
||||||
|
"#domain/*": [
|
||||||
|
"domain/*"
|
||||||
|
],
|
||||||
|
"#ports/*": [
|
||||||
|
"ports/*"
|
||||||
|
],
|
||||||
|
"#tests/*": [
|
||||||
|
"__tests__/*"
|
||||||
|
],
|
||||||
|
"#shared/*": [
|
||||||
|
"../shared/*"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"**/*.ts",
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"index.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { rabbitmqEventBus } from '#config/eventBusConfig';
|
import { rabbitmqEventBus } from '#config/eventBusConfig';
|
||||||
import { SimUsecases } from 'aplication/Sim.usecases';
|
import { SimUsecases } from 'aplication/Sim.usecases';
|
||||||
import { SimController } from 'aplication/SimController';
|
import { SimController } from 'aplication/Sim.controller';
|
||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
|
|
||||||
const simRoutes = Router()
|
const simRoutes = Router()
|
||||||
|
|||||||
22
yarn.lock
22
yarn.lock
@@ -2284,6 +2284,28 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"sim-consumidor-nos@workspace:packages/sim-consumidor-nos":
|
||||||
|
version: 0.0.0-use.local
|
||||||
|
resolution: "sim-consumidor-nos@workspace:packages/sim-consumidor-nos"
|
||||||
|
dependencies:
|
||||||
|
"@tsconfig/node22": "npm:*"
|
||||||
|
"@types/amqplib": "npm:^0.10.8"
|
||||||
|
"@types/cors": "npm:*"
|
||||||
|
"@types/express": "npm:*"
|
||||||
|
"@types/node": "npm:*"
|
||||||
|
"@types/supertest": "npm:*"
|
||||||
|
amqplib: "npm:^0.10.9"
|
||||||
|
cors: "npm:*"
|
||||||
|
dotenv: "npm:*"
|
||||||
|
express: "npm:*"
|
||||||
|
prettier: "npm:*"
|
||||||
|
supertest: "npm:*"
|
||||||
|
tsx: "npm:*"
|
||||||
|
typescript: "npm:*"
|
||||||
|
vitest: "npm:*"
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
"sim-consumidor@workspace:packages/sim-consumidor-activaciones":
|
"sim-consumidor@workspace:packages/sim-consumidor-activaciones":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "sim-consumidor@workspace:packages/sim-consumidor-activaciones"
|
resolution: "sim-consumidor@workspace:packages/sim-consumidor-activaciones"
|
||||||
|
|||||||
Reference in New Issue
Block a user