Mejorado el control de errores para ALAI

This commit is contained in:
2026-05-13 17:08:19 +02:00
parent b14464da39
commit d1e5892a0d
8 changed files with 97 additions and 28 deletions

View File

@@ -4,8 +4,8 @@ enableGlobalCache: false
nodeLinker: node-modules nodeLinker: node-modules
npmRegistryServer: "https://registry.npmjs.org/"
npmScopes: npmScopes:
sf-alvar: sf-alvar:
npmRegistryServer: "https://git.savefamilygps.net/api/packages/SaveFamily/npm/" npmRegistryServer: "https://git.savefamilygps.net/api/packages/SaveFamily/npm/"
npmRegistryServer: "https://registry.npmjs.org/"

View File

@@ -0,0 +1,38 @@
meta {
name: Alerts
type: http
seq: 23
}
get {
url: https://api-getway.objenious.com/ws/alarms
body: formUrlEncoded
auth: bearer
}
auth:bearer {
token: {{ws-access-token-partenaire}}
}
body:json {
{
"identifier": {
"identifiers": ["8933201124059175967"],
"identifierType": "ICCID"
}
}
}
body:form-urlencoded {
~identifier.identifierType: "ICCID"
~identifier.identifiers: ["8933201124059175967"]
}
vars:pre-request {
~id: 5187320
}
settings {
encodeUrl: true
timeout: 0
}

View File

@@ -1,7 +1,7 @@
{ {
"name": "sim-eventos", "name": "sim-eventos",
"version": "1.0.0", "version": "1.0.0",
"packageManager": "yarn@4.12.0", "packageManager": "yarn@4.14.1",
"workspaces": [ "workspaces": [
"packages/*" "packages/*"
], ],

View File

@@ -7,6 +7,11 @@ import { SimEvents } from "sim-shared/domain/SimEvents.js";
import { iccidValidator } from "./httpValidators.js"; import { iccidValidator } from "./httpValidators.js";
import { alaiSimToCommonSim } from "#domain/transformers.js"; import { alaiSimToCommonSim } from "#domain/transformers.js";
type ErrorUsecase = {
msg: string,
stackTrace?: string
}
export class SimAlaiController { export class SimAlaiController {
constructor( constructor(
@@ -41,12 +46,13 @@ export class SimAlaiController {
} }
} }
/** /**
* Metodo duplicado se puede generalizar la a una clase sharedController con las funciones basicas * Metodo duplicado se puede generalizar la a una clase sharedController con las funciones basicas
* TODO: meter un check de 429 * TODO: meter un check de 429
*/ */
private async tryUseCase<T extends any> private async tryUseCase<T extends any>
(msg: ConsumeMessage, usecase: () => Promise<Result<string, T>>): Promise<Result<string, T>> { (msg: ConsumeMessage, usecase: () => Promise<Result<ErrorUsecase, T>>): Promise<Result<ErrorUsecase, T>> {
try { try {
const result = await usecase() const result = await usecase()
if (result.error == undefined) { if (result.error == undefined) {
@@ -61,7 +67,10 @@ export class SimAlaiController {
console.error("Error general procesando el caso de uso (Alai)") console.error("Error general procesando el caso de uso (Alai)")
this.eventBus.nack(msg) this.eventBus.nack(msg)
return { return {
error: String(e) error: {
msg: String(e),
stackTrace: String(e)
}
} }
} }
} }

View File

@@ -10,13 +10,10 @@
*/ */
import { AlaiAPI } from "#domain/AlaiAPI.js"; import { AlaiAPI } from "#domain/AlaiAPI.js";
import { AlaiRepository } from "#infrastructure/AlaiRepository.js"; import { AlaiRepository } from "#infrastructure/AlaiRepository.js";
import { ConsumeMessage } from "amqplib";
import { error } from "node:console";
import { ErrorOrderDTO, FinishOrderDTO, UpdateOrderDTO } from "sim-shared/domain/Order.js"; import { ErrorOrderDTO, FinishOrderDTO, UpdateOrderDTO } from "sim-shared/domain/Order.js";
import { Result } from "sim-shared/domain/Result.js"; import { Result } from "sim-shared/domain/Result.js";
import { HttpClient } from "sim-shared/infrastructure/HTTPClient.js"; import { HttpClient } from "sim-shared/infrastructure/HTTPClient.js";
import { OrderRepository } from "sim-shared/infrastructure/OrderRepository.js"; import { OrderRepository } from "sim-shared/infrastructure/OrderRepository.js";
import { isOmittedExpression } from "typescript";
export class SimAlaiUsecases { export class SimAlaiUsecases {
constructor( constructor(
@@ -45,7 +42,7 @@ export class SimAlaiUsecases {
return order return order
} }
private async setFailed(correlation_id: string, reason: string, detail?: string) { private async setFailed(correlation_id: string, reason: string, stackTrace?: string) {
// En NOS el updateOrder se hace con el correlation_id que viene en la cabecera del // En NOS el updateOrder se hace con el correlation_id que viene en la cabecera del
// mensaje consumido // mensaje consumido
const updateData: ErrorOrderDTO = { const updateData: ErrorOrderDTO = {
@@ -53,7 +50,7 @@ export class SimAlaiUsecases {
correlation_id: correlation_id, correlation_id: correlation_id,
reason: reason, reason: reason,
error: reason, error: reason,
stackTrace: detail stackTrace: stackTrace
} }
console.log("SET FAILED DATA:", updateData) console.log("SET FAILED DATA:", updateData)
@@ -67,11 +64,11 @@ export class SimAlaiUsecases {
* a peticiones de lectura (no pasan por la cola y no generan un order) * a peticiones de lectura (no pasan por la cola y no generan un order)
*/ */
public usecaseTemplate<T, R>( public usecaseTemplate<T, R>(
func: (_: T) => Promise<Result<string, R>>, func: (_: T) => Promise<Result<{ msg: string, stackTrace?: string }, R>>,
args: T, args: T,
correlation_id?: string | undefined correlation_id?: string | undefined
) { ) {
return async (): Promise<Result<string, R>> => { return async (): Promise<Result<{ msg: string, stackTrace?: string }, R>> => {
// Operacion pending -> running // Operacion pending -> running
if (correlation_id != undefined) if (correlation_id != undefined)
this.setRunning(correlation_id) this.setRunning(correlation_id)
@@ -86,7 +83,7 @@ export class SimAlaiUsecases {
if (res.error != undefined) { if (res.error != undefined) {
console.log("Error peticion: ", res, correlation_id) console.log("Error peticion: ", res, correlation_id)
if (correlation_id != undefined) if (correlation_id != undefined)
this.setFailed(correlation_id, res.error) this.setFailed(correlation_id, res.error.msg, res.error.stackTrace)
.then(e => console.log("failed", e)) .then(e => console.log("failed", e))
.catch(e => console.error(e)) .catch(e => console.error(e))
return res; return res;
@@ -100,7 +97,9 @@ export class SimAlaiUsecases {
if (correlation_id != undefined) if (correlation_id != undefined)
this.setFailed(correlation_id, "Error general de operacion de SIM (NOS) ", String(e)).then() this.setFailed(correlation_id, "Error general de operacion de SIM (NOS) ", String(e)).then()
return { return {
error: "Error general de operacion de SIM (NOS) " + String(e) error: {
msg: "Error general de operacion de SIM (NOS) " + String(e)
}
} }
} }
@@ -119,7 +118,9 @@ export class SimAlaiUsecases {
if (sim.data == undefined) { if (sim.data == undefined) {
return { return {
error: `La sim ${iccid} no se ha encontrado` error: {
msg: `La sim ${iccid} no se ha encontrado`
}
} }
} }
@@ -127,7 +128,9 @@ export class SimAlaiUsecases {
if (subscriptionId == undefined) { if (subscriptionId == undefined) {
return { return {
error: `La sim ${iccid} no tiene un id de subscripción` error: {
msg: `La sim ${iccid} no tiene un id de subscripción`
}
} }
} }
@@ -244,7 +247,7 @@ export class SimAlaiUsecases {
* Para sacar los datos de una liena hay que sacar sim -> subscripcion -> imei * Para sacar los datos de una liena hay que sacar sim -> subscripcion -> imei
* son 3 llamadas distintas. * son 3 llamadas distintas.
*/ */
public async selectCompleteSim(iccid: string): Promise<Result<string, { public async selectCompleteSim(iccid: string): Promise<Result<{ msg: string, stackTrace?: string }, {
sim: AlaiAPI.Sim, sim: AlaiAPI.Sim,
subscription?: AlaiAPI.Subscription, subscription?: AlaiAPI.Subscription,
imei?: AlaiAPI.GetImeiSubscriptionDTO imei?: AlaiAPI.GetImeiSubscriptionDTO
@@ -257,7 +260,9 @@ export class SimAlaiUsecases {
if (sim.data == undefined) { if (sim.data == undefined) {
return { return {
error: `La sim ${iccid} no se ha encontrado` error: {
msg: `La sim ${iccid} no se ha encontrado`
}
} }
} }

View File

@@ -1 +1 @@
eyJhbGciOiJIUzM4NCJ9.eyJiciI6InNhdmVmYW1pbHkiLCJpcCI6Ijg4LjE1LjE1Ny4xNjciLCJzdWIiOiJwYWxvbWFpYmFuZXoiLCJzIjoiRVdTMTY3Mjc3OTE3YmVlMmU3IiwicG9zIjoic2F2ZWZhbWlseUNhYyIsImlkV3NVc2VyIjoiODYiLCJpc012bmEiOmZhbHNlLCJkb21haW4iOiJBbGFpfHNhdmVmYW1pbHkiLCJpYXQiOjE3Nzg2Njk5NTgsImV4cCI6MTc3ODY4MDc1N30.N_PZ3X2sMsMIs1gomG7eyCKyC8hev5EOeXIOZvQZelKwTkVX-U7P0Gbu6nhNeLyp eyJhbGciOiJIUzM4NCJ9.eyJiciI6InNhdmVmYW1pbHkiLCJpcCI6Ijg4LjE1LjE1Ny4xNjciLCJzdWIiOiJwYWxvbWFpYmFuZXoiLCJzIjoiRVdTMTY3MzRhYTM2MDY1M2EwIiwicG9zIjoic2F2ZWZhbWlseUNhYyIsImlkV3NVc2VyIjoiODYiLCJpc012bmEiOmZhbHNlLCJkb21haW4iOiJBbGFpfHNhdmVmYW1pbHkiLCJpYXQiOjE3Nzg2ODQ0NjIsImV4cCI6MTc3ODY5NTI2Mn0.wMWgjaOErm5clang7ErYzREU56okgpXWzq1zihT4lOfUDRQ005r-nCHJu7rpilj1

View File

@@ -14,7 +14,7 @@ export const alaiHttp = new HttpClient({
headers: { headers: {
"content-type": "application/json" "content-type": "application/json"
}, },
//jwtManager: tokenManager, jwtManager: tokenManager,
jwtManager: debugTokenManagr, //jwtManager: debugTokenManagr,
httpsAgent: httpsAgent httpsAgent: httpsAgent
}) })

View File

@@ -5,13 +5,18 @@ import { env } from "#config/env/env.js";
import { HttpClient } from "sim-shared/infrastructure/HTTPClient.js"; import { HttpClient } from "sim-shared/infrastructure/HTTPClient.js";
import https from "https" import https from "https"
type ErrorRepo = {
msg: string,
stackTrace?: string
}
export class AlaiRepository { export class AlaiRepository {
constructor( constructor(
private httpClient: HttpClient private httpClient: HttpClient
) { ) {
} }
private async manageRequest<E, T>(promiseReq: Promise<AxiosResponse<T>>): Promise<Result<string, T>> { private async manageRequest<E, T>(promiseReq: Promise<AxiosResponse<T>>): Promise<Result<ErrorRepo, T>> {
try { try {
const res = await promiseReq const res = await promiseReq
return { return {
@@ -19,19 +24,26 @@ export class AlaiRepository {
} }
} catch (e) { } catch (e) {
if (axios.isAxiosError(e)) { if (axios.isAxiosError(e)) {
console.log("ERROR REQUEST ", e.response)
const error = e as AxiosError const error = e as AxiosError
return { return {
error: error.code + " : " + String(error.response?.statusText) error: {
msg: error.code + " : " + String(error.response?.statusText),
stackTrace: JSON.stringify(error.response?.data)
}
} }
} else { } else {
return { return {
error: String(e) error: {
msg: String(e),
stackTrace: String(e)
}
} }
} }
} }
} }
public static async login(httpsAgent: https.Agent): Promise<Result<string, AlaiAPI.LoginResponseDTO>> { public static async login(httpsAgent: https.Agent): Promise<Result<ErrorRepo, AlaiAPI.LoginResponseDTO>> {
const alaiUrl = env.ALAI_API_URL const alaiUrl = env.ALAI_API_URL
const endpoint = "/v1/auth/login" const endpoint = "/v1/auth/login"
const fullUrl = alaiUrl + endpoint const fullUrl = alaiUrl + endpoint
@@ -50,11 +62,16 @@ export class AlaiRepository {
if (axios.isAxiosError(e)) { if (axios.isAxiosError(e)) {
const error = e as AxiosError const error = e as AxiosError
return { return {
error: error.code + " : " + String(error.response?.statusText) error: {
msg: error.code + " : " + String(error.response?.statusText),
stackTrace: String(error)
}
} }
} else { } else {
return { return {
error: String(e) error: {
msg: String(e)
}
} }
} }
} }
@@ -101,7 +118,7 @@ export class AlaiRepository {
/** /**
* Antes se usaba PATCH /v1/sim/{iccid}/{orderId} pero en la docu ha pasado a POST * Antes se usaba PATCH /v1/sim/{iccid}/{orderId} pero en la docu ha pasado a POST
*/ */
public async createReserve(orderId: string, iccid: string): Promise<Result<string, AlaiAPI.CreateOrderResponseDTO>> { public async createReserve(orderId: string, iccid: string): Promise<Result<ErrorRepo, AlaiAPI.CreateOrderResponseDTO>> {
const endpoint = `/v1/sim/${iccid}/order/${orderId}` const endpoint = `/v1/sim/${iccid}/order/${orderId}`
// Crear la reserva no usa datos en el body // Crear la reserva no usa datos en el body
const promReq = this.httpClient.post<AlaiAPI.CreateOrderResponseDTO>(endpoint, undefined) const promReq = this.httpClient.post<AlaiAPI.CreateOrderResponseDTO>(endpoint, undefined)