Problema de actuallizacion de operation resuelto

This commit is contained in:
2026-02-06 12:14:46 +01:00
parent 05138a44c9
commit 8a28c54c5d
9 changed files with 177 additions and 115 deletions

View File

@@ -5,19 +5,20 @@ CREATE TYPE status_enum AS ENUM ('noRequestID','noMassID','running','finished','
-- Para una o mas lineas se pueden lanzar operacione que no sabemos -- Para una o mas lineas se pueden lanzar operacione que no sabemos
-- con certeza cuando van a terminar. -- con certeza cuando van a terminar.
CREATE TABLE if not exists objenious_operation ( CREATE TABLE if not exists objenious_operation (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
retry_count INT DEFAULT 0, retry_count INT DEFAULT 0,
max_retry INT DEFAULT 5, max_retry INT DEFAULT 5,
max_date_retry TIMESTAMP DEFAULT NULL, max_date_retry TIMESTAMP DEFAULT NULL,
iccids TEXT, iccids TEXT,
request_id TEXT, request_id TEXT,
mass_action_id TEXT, mass_action_id TEXT,
operation TEXT NOT NULL, operation TEXT NOT NULL,
start_date TIMESTAMP NOT NULL DEFAULT now(), start_date TIMESTAMP NOT NULL DEFAULT now(),
last_change_date TIMESTAMP NOT NULL DEFAULT now(), last_change_date TIMESTAMP NOT NULL DEFAULT now(),
end_date TIMESTAMP, end_date TIMESTAMP,
error TEXT, error TEXT,
status status_enum status status_enum,
objenious_status TEXT
); );
-- operaciones pendientes para revisar -- operaciones pendientes para revisar
@@ -26,13 +27,17 @@ CREATE INDEX IF NOT EXISTS pending_operations
WHERE end_date IS NULL; WHERE end_date IS NULL;
CREATE TABLE if not exists objenious_operation_change ( CREATE TABLE if not exists objenious_operation_change (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
operation_id BIGINT, operation_id BIGINT,
creation_date TIMESTAMP NOT NULL DEFAULT now(), creation_date TIMESTAMP NOT NULL DEFAULT now(),
error TEXT, error TEXT,
new_status status_enum, new_status status_enum,
new_request_id TEXT, previous_status status_enum,
new_mass_action_id TEXT, new_objenious_status TEXT,
previous_objenious_status TEXT,
new_request_id TEXT,
new_mass_action_id TEXT,
CONSTRAINT fk_operation_id CONSTRAINT fk_operation_id
FOREIGN KEY(operation_id) REFERENCES objenious_operation(id) FOREIGN KEY(operation_id) REFERENCES objenious_operation(id)
); );

View File

@@ -109,19 +109,20 @@ CREATE TYPE status_enum AS ENUM ('noRequestID','noMassID','running','finished','
-- Para una o mas lineas se pueden lanzar operacione que no sabemos -- Para una o mas lineas se pueden lanzar operacione que no sabemos
-- con certeza cuando van a terminar. -- con certeza cuando van a terminar.
CREATE TABLE if not exists objenious_operation ( CREATE TABLE if not exists objenious_operation (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
retry_count INT DEFAULT 0, retry_count INT DEFAULT 0,
max_retry INT DEFAULT 5, max_retry INT DEFAULT 5,
max_date_retry TIMESTAMP DEFAULT NULL, max_date_retry TIMESTAMP DEFAULT NULL,
iccids TEXT, iccids TEXT,
request_id TEXT, request_id TEXT,
mass_action_id TEXT, mass_action_id TEXT,
operation TEXT NOT NULL, operation TEXT NOT NULL,
start_date TIMESTAMP NOT NULL DEFAULT now(), start_date TIMESTAMP NOT NULL DEFAULT now(),
last_change_date TIMESTAMP NOT NULL DEFAULT now(), last_change_date TIMESTAMP NOT NULL DEFAULT now(),
end_date TIMESTAMP, end_date TIMESTAMP,
error TEXT, error TEXT,
status status_enum status status_enum,
objenious_status TEXT
); );
-- operaciones pendientes para revisar -- operaciones pendientes para revisar
@@ -130,13 +131,17 @@ CREATE INDEX IF NOT EXISTS pending_operations
WHERE end_date IS NULL; WHERE end_date IS NULL;
CREATE TABLE if not exists objenious_operation_change ( CREATE TABLE if not exists objenious_operation_change (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
operation_id BIGINT, operation_id BIGINT,
creation_date TIMESTAMP NOT NULL DEFAULT now(), creation_date TIMESTAMP NOT NULL DEFAULT now(),
error TEXT, error TEXT,
new_status status_enum, new_status status_enum,
new_request_id TEXT, previous_status status_enum,
new_mass_action_id TEXT, new_objenious_status TEXT,
previous_objenious_status TEXT,
new_request_id TEXT,
new_mass_action_id TEXT,
CONSTRAINT fk_operation_id CONSTRAINT fk_operation_id
FOREIGN KEY(operation_id) REFERENCES objenious_operation(id) FOREIGN KEY(operation_id) REFERENCES objenious_operation(id)
); );

View File

@@ -5,14 +5,14 @@ meta {
} }
get { get {
url: {{actionsUrl}}/requests/?pageSize=100&request.actionType=PREACTIVAION url: {{actionsUrl}}/requests/?pageSize=10
body: formUrlEncoded body: formUrlEncoded
auth: bearer auth: bearer
} }
params:query { params:query {
pageSize: 100 pageSize: 10
request.actionType: PREACTIVAION ~request.actionType: PREACTIVAION
} }
auth:bearer { auth:bearer {

View File

@@ -1,5 +1,5 @@
meta { meta {
name: Mass action copy name: Mass action by id
type: http type: http
seq: 15 seq: 15
} }
@@ -24,7 +24,7 @@ body:json {
} }
vars:pre-request { vars:pre-request {
id: 5189837 id: 5192767
} }
settings { settings {

View File

@@ -5,27 +5,34 @@ meta {
} }
get { get {
url: {{actionsUrl}}/massActions/ url: {{actionsUrl}}/massActions?massActionId=5192767
body: formUrlEncoded body: formUrlEncoded
auth: bearer auth: bearer
} }
params:query {
massActionId: 5192767
~identifier.identifierType: ICCID
~identifier.identifiers: 8933201125065160463,8933201125065160422
}
auth:bearer { auth:bearer {
token: {{ws-access-token-partenaire}} token: {{ws-access-token-partenaire}}
} }
body:json { body:json {
{
"identifier": { "identifier": {
"identifiers": ["8933201124059175967"], "identifiers": ["8933201124059175967"],
"identifierType": "ICCID" "identifierType": "ICCID"
} }
}
} }
body:form-urlencoded { body:form-urlencoded {
identifier.identifierType: ICCID identifier.identifierType: ICCID
identifier.identifiers: 8933201124059176320 identifier.identifiers: 8933201125065160463
~massActionId: 5192767
} }
vars:pre-request { vars:pre-request {

View File

@@ -1,5 +1,5 @@
import axios, { AxiosInstance } from "axios" import axios, { AxiosInstance } from "axios"
import { JWTToken } from "../domain/JWT" import { JWTToken } from "../domain/JWT.js"
export type JWTProvider<T> = { export type JWTProvider<T> = {
/** El servidor está solicitando un token nuevo o refrescando el actual*/ /** El servidor está solicitando un token nuevo o refrescando el actual*/
@@ -49,7 +49,7 @@ export class HttpClient {
async (error) => { async (error) => {
// TODO: Esta parte no tiene tipos, hay que asegurar el error // TODO: Esta parte no tiene tipos, hay que asegurar el error
const req = error.config const req = error.config
console.error("[http] Error en la respuesta ", error.response.data) console.error("[http] Error en la respuesta ", error, error.response)
if (error.response?.status == 401) { if (error.response?.status == 401) {
this.jwtManager.getAccessToken() this.jwtManager.getAccessToken()
} }

View File

@@ -1,6 +1,6 @@
import { Result } from "#shared/domain/Result.js"; import { Result } from "#shared/domain/Result.js";
export type StatusEnum = Objenious.Status | 'noMassID'; export type StatusEnum = 'error' | 'finished' | 'noRequestId' | 'running' | 'noMassID';
export interface IOperationsRepository { export interface IOperationsRepository {
createOperation(data: ObjeniousOperation): Promise<Result<string, ObjeniousOperation>> createOperation(data: ObjeniousOperation): Promise<Result<string, ObjeniousOperation>>
@@ -20,6 +20,7 @@ export type ObjeniousOperation = {
end_date?: Date | null; end_date?: Date | null;
error?: string | null; error?: string | null;
status: StatusEnum; status: StatusEnum;
objenioius_status: string;
last_change_date?: string; last_change_date?: string;
} }
@@ -29,6 +30,9 @@ export type ObjeniousOperationChange = {
info?: string | null; info?: string | null;
error?: string | null; error?: string | null;
new_status: StatusEnum; new_status: StatusEnum;
previous_status?: StatusEnum;
new_objenious_status?: string;
previous_objenious_status?: string;
new_request_id?: string; new_request_id?: string;
new_mass_action_id?: string; new_mass_action_id?: string;
} }

View File

@@ -16,8 +16,8 @@ export class OperationsRepository implements IOperationsRepository {
INSERT INTO objenious_operation (operation, iccids, status, max_retry, request_id) INSERT INTO objenious_operation (operation, iccids, status, max_retry, request_id)
VALUES ($1, $2, $3, $4, $5) VALUES ($1, $2, $3, $4, $5)
RETURNING *`; RETURNING *`;
const iccids = data.iccids.join(",") const iccids = JSON.stringify(data.iccids)
const values = [data.operation, data.iccids, data.status, data.max_retry, data.request_id]; const values = [data.operation, iccids, data.status, data.max_retry, data.request_id];
const { rows } = await this.pgClient.query(query, values); const { rows } = await this.pgClient.query(query, values);
return <Result<string, ObjeniousOperation>>{ return <Result<string, ObjeniousOperation>>{
data: rows[0] data: rows[0]
@@ -26,34 +26,52 @@ export class OperationsRepository implements IOperationsRepository {
async updateOperation(data: ObjeniousOperationChange): Promise<Result<string, ObjeniousOperation>> { async updateOperation(data: ObjeniousOperationChange): Promise<Result<string, ObjeniousOperation>> {
const client = await this.pgClient.connect(); const client = await this.pgClient.connect();
const { new_status, error, new_request_id, new_mass_action_id, id } = data const {
new_status,
previous_status,
error,
new_request_id,
new_mass_action_id,
operation_id,
new_objenious_status,
previous_objenious_status
} = data
try { try {
await client.query('BEGIN'); await client.query('BEGIN');
// 1. Actualizar objenious_operation (la operacion base)
// 1. Actualizar objenious_operation const updateParams = [operation_id, new_status, error, new_request_id, new_mass_action_id, new_objenious_status]
console.log("updateParams", updateParams)
const updateOpQuery = ` const updateOpQuery = `
UPDATE objenious_operation UPDATE objenious_operation
SET SET
status = $1, status = $2::status_enum,
error = COALESCE($2,error), error = COALESCE($3,error),
request_id = COALESCE($3, request_id), request_id = COALESCE($4, request_id),
mass_action_id = COALESCE($4, mass_action_id), mass_action_id = COALESCE($5, mass_action_id),
last_change_date = now(), last_change_date = now(),
end_date = CASE WHEN $1 IN ('finished', 'error') THEN now() ELSE end_date END end_date = CASE WHEN $2::status_enum IN ('finished', 'error') THEN now() ELSE end_date END,
WHERE id = $5`; objenious_status = $6
const operation = await client.query<ObjeniousOperation>(updateOpQuery, [new_status, error, new_request_id, new_mass_action_id, id]); WHERE id = $1`;
// 2. Nuevo registro en objenious_operation_change const operation = await client.query<ObjeniousOperation>(
updateOpQuery, updateParams)
console.log("Operacion base acualizada")
// 2. Nuevo registro en objenious_operation_change (indica un cambio de estado)
const insertChangeQuery = ` const insertChangeQuery = `
INSERT INTO objenious_operation_change (operation_id, new_status, error, new_request_id, new_mass_action_id) INSERT INTO objenious_operation_change (operation_id, new_status, previous_status, error, new_request_id, new_mass_action_id, new_objenious_status, previous_objenious_status)
VALUES ($1, $2, $3, $4, $5)`; VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`;
await client.query(insertChangeQuery, [id, new_status, error, new_request_id, new_mass_action_id]); await client.query(insertChangeQuery, [operation_id, new_status, previous_status, error, new_request_id, new_mass_action_id, new_objenious_status, previous_objenious_status]);
console.log("Nuevo registro de actualizacion")
await client.query('COMMIT'); await client.query('COMMIT');
return <Result<string, ObjeniousOperation>>{ return <Result<string, ObjeniousOperation>>{
data: operation.rows[0] data: operation.rows[0]
} }
} catch (e) { } catch (e) {
console.error("Error añadiendo actualizacion de la operation", e)
console.error("datos errorneos", data)
await client.query('ROLLBACK'); await client.query('ROLLBACK');
return <Result<string, ObjeniousOperation>>{ return <Result<string, ObjeniousOperation>>{
data: undefined, data: undefined,

View File

@@ -1,5 +1,6 @@
import { IOperationsRepository, Objenious, ObjeniousOperation, ObjeniousOperationChange } from "#objenious-shared/domain/operationsRepository.port.js" import { IOperationsRepository, Objenious, ObjeniousOperation, ObjeniousOperationChange, StatusEnum } from "#objenious-shared/domain/operationsRepository.port.js"
import { HttpClient } from "#shared/infrastructure/HTTPClient.js"; import { HttpClient } from "#shared/infrastructure/HTTPClient.js";
import { constants } from "node:buffer";
export class CheckObjeniousRequests { export class CheckObjeniousRequests {
constructor( constructor(
@@ -52,71 +53,93 @@ export class CheckObjeniousRequests {
if (requestList.length == 0) return; if (requestList.length == 0) return;
const operationsList = structuredClone(requestList) const operationsList = structuredClone(requestList)
const PATH = "/actions/massActions" const PATH = "/actions/massActions/"
const updated = [] const updated = []
const iccids = operationsList const iccids = operationsList
.map(e => e.iccids) .map(e => e.iccids)
.flat() .flat()
const mass_actions = operationsList
.filter(e => e.mass_action_id != undefined)
const iccidSet = new Set<string>(iccids) const iccidSet = new Set<string>(iccids)
console.log("iccidSet", iccidSet)
const req = this.httpClient.client.get<Objenious.ResponseGetMassAction[]>(PATH, { // 1. Una peticion por cada accion a comprobar
params: <Objenious.ParametersGetMassAction>{ // Las peticiones por iccid u otro filtro tardan ~50s
"identifier.identifierType": "ICCID", for (const originalAction of mass_actions) {
"identifier.identifiers": Array.from(iccidSet)
}
})
let res;
// 1. Comprobacion de la request.
try {
res = await req
} catch (e) {
console.error("Error comprobando el estado de ", iccidSet, e)
return;
}
const { data, status } = res const req = this.httpClient.client.get<Objenious.ResponseGetMassAction>(PATH + originalAction.mass_action_id, {
params: <Objenious.ParametersGetMassAction>{
if (status != 200 || data == undefined) {
console.error("Error buscando los massActions")
return
}
if (data.length == 0) return;
// 2. Por cada elemento de la respuesta se comprueba si ha habido un cambio de estado
for (const action of data) {
const { id, status } = action
const original = operationsList.find(e => e.id == id)
console.log("Comprobando", action, original)
if (original == undefined) continue;
if (status != original?.status) {
console.log("Actualizando", action, original)
const updateData: ObjeniousOperationChange = {
operation_id: original.id!,
new_status: status,
} }
original.status = status; })
original.last_change_date = new Date().toISOString()
if (action.info != undefined) { let res;
updateData.info = action.info // 1. Comprobacion de la request.
try {
res = await req
} catch (e) {
console.error("Error comprobando el estado de ", originalAction)
console.error("Error: ", e)
return;
}
const { data } = res
console.log("Estado de : ", originalAction.mass_action_id, originalAction.iccids)
console.log(res.status, data)
if (res.status != 200 || data == undefined) {
console.error("Error buscando los massActions")
continue;
}
// 2. Se comprueba si ha habido un cambio de estado
const { id, status, info } = data
if (status != originalAction.objenioius_status) {
console.log("Actualizando", originalAction, status)
const uorStatus = this.mapStatus(status)
const updateData: ObjeniousOperationChange = {
operation_id: originalAction.id!,
new_objenious_status: status,
previous_objenious_status: originalAction.objenioius_status,
new_status: uorStatus,
previous_status: originalAction.status
}
originalAction.status = uorStatus;
originalAction.objenioius_status = status;
originalAction.last_change_date = new Date().toISOString()
if (info != undefined) {
updateData.info = info
} }
try { try {
console.log("Subiendo un update")
console.log(updateData)
await this.operationsRepository.updateOperation(updateData) await this.operationsRepository.updateOperation(updateData)
updated.push(action) updated.push(originalAction)
} catch (e) { } catch (e) {
console.error("Error actualizando el estado de ", action, e) console.error("Error actualizando el estado de ", originalAction, e)
return; return;
} }
} }
} }
}
private mapStatus(objStatus: string) {
const sanitizedStatus = objStatus.trim().toLowerCase()
// No tengo el resto porque no aparecen en la documentación
// asumo que todos los demas sn running y se deben volver a comrobar
const equivalentMap = new Map<string, StatusEnum>([
["terminé", "finished"]
])
const res = equivalentMap.get(objStatus)
if (res == undefined) return "running"
return res
} }
/** /**
@@ -154,7 +177,7 @@ export class CheckObjeniousRequests {
if (res.status == 200 && res.data != undefined && massActionId != undefined) { if (res.status == 200 && res.data != undefined && massActionId != undefined) {
const updateData: ObjeniousOperationChange = { const updateData: ObjeniousOperationChange = {
operation_id: request.id, operation_id: request.id,
new_status: "IN_PROGRESS", new_status: "running",
new_mass_action_id: String(massActionId) new_mass_action_id: String(massActionId)
} }
@@ -163,7 +186,7 @@ export class CheckObjeniousRequests {
request.mass_action_id = String(massActionId) request.mass_action_id = String(massActionId)
} }
} catch (e) { } catch (e) {
console.log("Error actualizando ell estado de ", request) console.log("Error actualizando el estado de ", request)
continue; continue;
} }