Verifica della presenza di email duplicate nei dati di risposta api

Aug 20 2020

Sto lavorando a una piccola app interna che funziona con un'API esterna a scopo di provisioning.

Il codice è essenzialmente costituito da una serie di moduli in cui l'utente inserisce i dati, questi dati vengono quindi inviati all'API per registrare nuovi clienti.

Questo è un processo piuttosto lineare che cercherò di spiegare:

  1. Creazione contatto: informazioni di base del cliente (e-mail, indirizzo ...).
  2. Creazione del cliente: informazioni più avanzate, per creare un cliente deve esserci contactIdun'appartenenza a questo cliente.
  3. Creazione abbonato: informazioni che collegano il cliente al servizio acquisito. Il passaggio precedente deve essere completato e customerIddeve esistere.
  4. Creazione servizio: ultimi bit di informazioni avanzate sul servizio. Ancora una volta, suscriberIddeve esistere per collegare il servizio.

Ho gestito un processo più o meno veloce con alcune modifiche qua e là, ma il primo passaggio (Contatto) ha un metodo che non riesco a migliorare, che a sua volta fa sì che questo processo richieda fino a un minuto intero !

Come l'intero processo descritto in precedenza, anche la creazione di ciascuno di questi è molto lineare.

La documentazione API afferma che i risultati di qualsiasi GET devono essere impaginati fino a un massimo di 10 voci, ma in seguito a ciò aumenta ulteriormente il tempo nel minuto. Gli esperimenti manuali hanno mostrato che il rapporto migliore è di circa 500 voci per pagina o, in alcuni casi, anche l'intero numero di voci si è rivelato il modo più veloce piuttosto che 10 per 10.

Poiché l'email di contatto non può essere duplicata, una delle prime cose da fare è controllare l'email fornita nel modulo e confrontarla con tutte le email già esistenti archiviate.

Per fornire il $pagee $entriesalla chiamata API, devo prima recuperare il numero totale di contatti. Questo numero viene visualizzato quando si chiama l'API per ottenere i contatti. Quindi il primo metodo che uso è:

function fetchTotalContacts($uri, $auth){
    $ch = curl_init(); $options = array(
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_SSL_VERIFYHOST => false,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_URL => $uri.'?page=1&rows=1', CURLOPT_HTTPHEADER => array('Content-Type: application/json', 'Authorization: $auth')
    );

    curl_setopt_array($ch, $options);

    $response = curl_exec($ch);
    $response = json_decode($response, true);
    $totalContacts = $response['total_count'];

    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    if ($http_code != 200) { echo "Error en fetchTotalContacts() - Código: $http_code | ";
    }
    
    curl_close($ch); return $totalContacts;
}

Ora $totalContacts, posso procedere e cercare se l'e-mail è già stata registrata, e questo è il passaggio che sospetto sia responsabile dell'elevato tempo di esecuzione. Questo metodo ricerca i contatti e le loro email, se non trova coincidenza, procede alla creazione del contatto con i dati forniti.

function checkDuplicatedEmail($uri, $totalContacts, $contactEmailArray, $auth, $contactEmail, $dataContact){ $ch = curl_init();

    $options = array( CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_URL => $uri.'?page=1&rows='.$totalContacts, CURLOPT_HTTPHEADER => array('Content-Type: application/json', 'Authorization: $auth')
    );
    curl_setopt_array($ch, $options);

    $customers = curl_exec($ch);
    $customers = json_decode($customers, true);

    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    
    if ($http_code != 200) { echo "Error en checkDuplicatedEmail() - Código: $http_code | ";
    }


    curl_close($ch); /* foreach ($customers['_embedded']['ngcp:customercontacts'] as $customer) { $email = $customer['email']; array_push($contactEmailArray, $email); } if (in_array($contactEmail, $contactEmailArray)) { echo('El email utilizado ya ha sido registrado en la base de datos'); die(); }else{ $contactCreated = createContact($uri, $dataContact);
        return $contactCreated; } */ $repeated = 0;
    for ($i=0; $i < $totalContacts ; $i++) {
        if ($contactEmail == $customer["_embedded"]["ngcp:customercontacts"][$i]["email"]) { $repeated += 1;
        }
    }

    if ($repeated > 0) { die(echo('El email utilizado ya ha sido registrado en la base de datos')); }else{ $contactCreated = createContact($uri, $dataContact, $auth); return $contactCreated;
    }
}

Come puoi vedere, queste sono le opzioni più veloci che ho trovato, entrambe fanno sì che l'intero processo richieda 40 secondi, il che è ancora troppo.

La risposta per è un codice di successo (400, 201 ..), quindi quando voglio andare al passaggio successivo devo, ancora una volta, cercare tutti i contatti per trovare quello che ho appena creato e ottenere l'id. Fortunatamente, qui posso semplicemente saltare agli ultimi 20 contatti (non l'ultimo direttamente in modo che possa essere utilizzato contemporaneamente senza problemi) e cercare lì, questo lo rende davvero veloce, ma per l'email non c'è un tale salto, tutte le voci deve essere analizzato.createContact($uri, $dataContact, $auth);

Non so come far cadere il tempo qui, il resto del codice consiste nel recuperare contactIde creare il cliente in modo che non ci sia molto da fare lì come lo è ora.

Se qualcuno di voi riterrà necessario vedere il resto della pagina aggiornerò il post.

Come promemoria finale, ho provato manualmente con diverse configurazioni di pagine e voci e per questa pagina, il più veloce è stato 1 page - All entries. Ho anche provato a prendere il ciclo for / each al di fuori del metodo, senza alcun risultato.

Risposte

2 mickmackusa Aug 20 2020 at 20:27

Il forloop non sarà il collo di bottiglia nel tuo loop, ma ciò che mi sembra ovvio è che non trai vantaggio dal conteggio più alto di $repeated = 1. Ciò significa che non è necessaria una variabile contatore, in realtà è necessario un evento di interruzione del ciclo, in questo caso die(). Per tua informazione, die()stamperà il testo nel suo primo parametro, quindi l'utilizzo echoè ridondante.

for ($i=0; $i < $totalContacts; ++$i) { if ($contactEmail == $customer["_embedded"]["ngcp:customercontacts"][$i]["email"]) {
        die('El email utilizado ya ha sido registrado en la base de datos');
    }
}
return createContact($uri, $dataContact, $auth);

O un altro modo, che presumo sarà più lento (perché array_column()raccoglierà tutte le email) è questo design funzionale:

if (in_array($contactEmail, array_column($customer["_embedded"]["ngcp:customercontacts"], "email"))) { die('El email utilizado ya ha sido registrado en la base de datos'); } return createContact($uri, $dataContact, $auth);