0

quiero leer un json que recibo por Api, tiene una longitud de 5.000 a 10.000 lineas, el tiempo de espera para leerlo y meterlo en la BD supera el minuto y medio, más medio minuto que tardo recibirlo de la Api. Todo esto suma 2 minutos o más, tiempo que el usuario debe esperar para poder seguir trabajando en la aplicación,

Estoy usando un share hosting, no puedo instalar un servicio como Redis (segun tengo entendido), para dejar él proceso en cola y que el usuario pueda seguir navegando.

Pregunta: ?Existe algun método para leer json de una forma mas "rápida", o forma para que el proceso pueda desarrollarse sin impedir que el usuario siga trabajando? Probé Ajax, pero de todos modos si quiero cargar otra vista, inevitablemente espera a que el proceso termine para hacer un redirect.

Comparto parte del cuerpo del json y la función del controlador que uso para meter el json en la base de datos.

JSON:

 "id": “xxxxxxxx”,
    "organization_id": "xxxxxxxx",
    "project_id": "xxxxxxxx",
    "status": "planning",
    "label": “/de”mo,
    "optimizer_config": {
        "max_wait_time": 3600,
        "time_limit_seconds": 240,
        "balance_services": false,
        "service_duration": 300,
        "operation_country": "AR",
        "distance_span_coefficient": 0,
        "time_span_coefficient": 0,
        "distance_balance": 2,
        "isolation_factor": 1
    },
    "traffic_options": {
        "multiplier": 2.5,
        "mode": "car"
    },
    "completed_stops": 0,
    "canceled_stops": 0,
    "pending_stops": 0,
    "total_stops": 174,
    "total_drivers": 0,
    "stops": [
        {
            "id": "xxxxxxxx",
            "project_id": "xxxxxxxx",
            "plan_id": "xxxxxxxx",
            "label": "xxxxxxxx García",
            "type": "xxxxxxxx",
            "status": "pending",
            "location": {
                "label": "xxxxxxxx 2241, Buenos Aires"
            },
            "location_details": "2n 3ª",
            "custom_fields": {},
            "time_windows": [],
            "requires": [],
            "duration": 300,
            "tasks": [],
            "events": [
                {
                    "created_at": "2024-04-16T18:50:53.814Z",
                    "created_by": "xxxxxxxx",
                    "object_id": "xxxxxxxx",
                    "type": "sxxxxxxxx"
                }
            ],
            "reports": [],
            "pin": "PJ1",
            "supervisors": [],
            "deleted": false,
            "created_by": "xxxxxxxx",
            "created_at": "2024-04-16T18:50:53.715Z"
        },
        {
            "id": "xxxxxxxx",
            "project_id": "xxxxxxxx",
            "plan_id": "xxxxxxxx",
            "label": "Júlia xxxxxxxx",
            "type": "xxxxxxxx",
            "status": "pending",
            "location": {
                "label": "Av. xxxxxxxx 2111 CABA"
            },
            "location_details": "4t 1ª, esc. xxxxxxxx",
            "custom_fields": {},
            "time_windows": [],
            "requires": [],
            "duration": 300,
            "tasks": [],
            "events": [
                {
                    "created_at": "2024-04-16T18:50:54.004Z",
                    "created_by": "xxxxxxxx",
                    "object_id": "xxxxxxxx",
                    "type": "xxxxxxxx"
                }
            ],
            "reports": [],
            "pin": "GU6",
            "supervisors": [],
            "deleted": false,
            "created_by": "xxxxxxxx",
            "created_at": "2024-04-16T18:50:53.927Z"
        }... 

... ... ...,….

Funcion del controlador donde paso por $request el json:

public function crearPlanActualizarDB(Request $request)
    { 
        
        $apiResponse = $request->getBody()->getContents();

        $responseArray = json_decode($apiResponse, true);

        foreach ($responseArray['stops'] as $stop) {
        
            $tabla = Tablamaster::where('id', $stop['custom_fields']['id'])->first();
            
            if ($tabla) {
                $relaciones = [];
                $relaciones[] = ['variable' => 'Chofer', 'valor' => 'S/D'];
                $relaciones[] = ['variable' => 'Parada', 'valor' => 'S/D'];
                $relaciones[] = ['variable' => 'Estado', 'valor' => isset($stop['status']) ? $stop['status'] : "S/D"];
                $nombrePlan = $this->obtenerNombrePlan($stop['plan_id']);
                $relaciones[] = ['variable' => 'Plan', 'valor' =>  isset($stop['label']) ? $nombrePlan : "S/D"];
                $relaciones[] = ['variable' => 'IDPlan', 'valor' => $stop['plan_id']];
                if (!empty($relaciones)) {
                    $tabla->relaciones()->createMany($relaciones);
                }
                // Actualizamos la columna 'id_chofer_sm'
                $tabla->update(['id_chofer_sm' => $stop['id']]);
            } 
        }
        return response()->json([
            'message' => 'Procesamiento 2 exitoso',
            
        ], 200);
        
    }

Muchas gracias.

2
  • 1
    Asígnale un ID a la llamada de front, guárdalo en la base de datos y devuélvelo a front. En background vas descargando y parseando el json, desde front vas haciendo polling (llamando cada X segundos) a tu backend pasándole el nº de tarea. En backend solo tienes que mirar si el ID está como completado en la base de datos, si está, puedes leer los datos que quieras devolverle, si no, simplemente devuelves un flag a false para que continúe el polling. En tu proceso en segundo plano una vez termine de parsear actualizas el estado de esa ID en la base de datos. Esta solo es una manera, hay otras :)
    – Benito-B
    Commented el 24 abr. a las 6:05
  • Hola Benito, a ver si entendi, guardo el Json, en BD, no lo proceso, hago que el usuario siga su trabajo en la aplicacion, y mientras tanto voy haciendo este proceso que decis. Gracias por la respuesta
    – ClaudioZ
    Commented el 24 abr. a las 13:53

1 respuesta 1

0

Tuve un problema similar con archivos csv, lo que aplique fue hacer inserciones por lotes, asi es más rapido, te dejo el ejemplo

 $apiResponse = $request->getBody()->getContents();
    $responseArray = json_decode($apiResponse, true);
    $stops = $responseArray['stops'];
    
    // Usar transacción
    DB::beginTransaction();
    try {
        foreach (array_chunk($stops, 200) as $chunk) {
            foreach ($chunk as $stop) {
                // La logica que quieres aplicar, si es web es un maximo de 2100 parametros
            }
        }
        DB::commit();
        return response()->json(['message' => 'Procesamiento exitoso'], 200);
    } catch (\Exception $e) {
        DB::rollback();
        return response()->json(['message' => 'Error en el procesamiento', 'error' => $e->getMessage()], 500);
    }
1
  • Hola, gracias por la respuesta, voy a ver tu codigo y a tirar algunas pruebitas. Gracias @completoitaliano : )
    – ClaudioZ
    Commented el 26 abr. a las 18:33

¿No es la respuesta que buscas? Examina otras preguntas con la etiqueta o formula tu propia pregunta.