Update ChronoTrack API synchronization parameters to improve performance and error handling. Increase chunk sizes for data processing and adjust timeout settings for HTTP requests. Introduce adaptive entry posting to handle failures more efficiently, reducing the number of HTTP calls. This change enhances the reliability and efficiency of participant data synchronization.

This commit is contained in:
2026-07-14 09:53:14 -04:00
parent 13e6f6dcf2
commit d1733b2848
3 changed files with 99 additions and 65 deletions

View File

@ -1001,7 +1001,7 @@ function fxChronotrackApiAdminRenderPageScript($intEveId, $arrConfig, $blnClosed
}
var $btn = $(this);
var $res = $('#ct_api_push_result');
var intChunk = 50;
var intChunk = 250;
var intOffset = 0;
var intTotal = intEligible;
var intOkSum = 0;

View File

@ -22,8 +22,8 @@ function fxChronotrackApiHttpRequest($strMethod, $strUrl, $arrOptions = array())
curl_setopt($ch, CURLOPT_URL, $strUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
curl_setopt($ch, CURLOPT_TIMEOUT, 180);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $arrHeaders);

View File

@ -3,10 +3,10 @@
* MSIN API ChronoTrack — Phase 2a : lecture MS1, diff, push manuel entries.
*/
// Lot POST ChronoTrack (créations). Plus gros = moins daller-retours HTTP (MSIN-4328).
define('MSIN_API_CHRONOTRACK_SYNC_BATCH_SIZE', 50);
// Taille dun chunk AJAX (barre davancement côté admin).
define('MSIN_API_CHRONOTRACK_SYNC_CHUNK_SIZE', 50);
// Lot POST ChronoTrack — aligné sur un import fichier (MSIN-4328).
define('MSIN_API_CHRONOTRACK_SYNC_BATCH_SIZE', 250);
// Chunk AJAX = même taille (1 requête navigateur ≈ 1 POST CT).
define('MSIN_API_CHRONOTRACK_SYNC_CHUNK_SIZE', 250);
function fxChronotrackApiSyncIso2ToIso3($strIso2) {
static $tabMap = null;
@ -553,18 +553,35 @@ function fxChronotrackApiSyncPostEntries($intCtEventId, array $tabEntries) {
return array('state' => 'error', 'message' => 'Aucune entry à envoyer');
}
static $strBodyFormat = 'array';
if ($strBodyFormat === 'event_entry') {
$arrPost = fxChronotrackApiOAuthApiPost(
'event/' . $intCtEventId . '/entry',
array('event_entry' => $tabEntries)
);
if ($arrPost['state'] === 'ok') {
$arrPost['body_format'] = 'event_entry';
return $arrPost;
}
return $arrPost;
}
// Doc CT : POST body = tableau JSON d'entités entry (pas de wrapper event_entry).
$arrPost = fxChronotrackApiOAuthApiPost('event/' . $intCtEventId . '/entry', $tabEntries);
if ($arrPost['state'] === 'ok') {
$arrPost['body_format'] = 'array';
$strBodyFormat = 'array';
return $arrPost;
}
// Essai wrapper une seule fois (mémoire du format si succès).
$arrPostWrap = fxChronotrackApiOAuthApiPost(
'event/' . $intCtEventId . '/entry',
array('event_entry' => $tabEntries)
);
if ($arrPostWrap['state'] === 'ok') {
$strBodyFormat = 'event_entry';
$arrPostWrap['body_format'] = 'event_entry';
return $arrPostWrap;
}
@ -574,6 +591,55 @@ function fxChronotrackApiSyncPostEntries($intCtEventId, array $tabEntries) {
return $arrPost;
}
/**
* POST entries avec découpage dichotomique si le lot échoue (évite 250 appels unitaires).
* MSIN-4328
*/
function fxChronotrackApiSyncPostEntriesAdaptive($intCtEventId, array $tabEntries, array &$tabErrors, $intEveId = 0, array $tabMeta = array()) {
$intCount = count($tabEntries);
if ($intCount === 0) {
return array('ok' => 0, 'err' => 0);
}
$arrPost = fxChronotrackApiSyncPostEntries($intCtEventId, $tabEntries);
if ($arrPost['state'] === 'ok') {
return array('ok' => $intCount, 'err' => 0);
}
if ($intCount === 1) {
$arrM = $tabMeta[0] ?? array('par_id' => 0, 'external_id' => '');
$strOneErr = $arrPost['message'] ?? 'Erreur POST entry';
if (count($tabErrors) < 12) {
$tabErrors[] = 'external_id=' . ($arrM['external_id'] ?? '') . ' — ' . $strOneErr;
}
if ($intEveId > 0) {
fxChronotrackApiSyncLog($intEveId, intval($arrM['par_id'] ?? 0), 'push_entry', 'error',
'external_id=' . ($arrM['external_id'] ?? '') . ' — ' . $strOneErr);
}
return array('ok' => 0, 'err' => 1);
}
$intMid = (int)floor($intCount / 2);
$arrLeft = fxChronotrackApiSyncPostEntriesAdaptive(
$intCtEventId,
array_slice($tabEntries, 0, $intMid),
$tabErrors,
$intEveId,
array_slice($tabMeta, 0, $intMid)
);
$arrRight = fxChronotrackApiSyncPostEntriesAdaptive(
$intCtEventId,
array_slice($tabEntries, $intMid),
$tabErrors,
$intEveId,
array_slice($tabMeta, $intMid)
);
return array(
'ok' => $arrLeft['ok'] + $arrRight['ok'],
'err' => $arrLeft['err'] + $arrRight['err'],
);
}
function fxChronotrackApiSyncProbePush($intEveId) {
$arrConfig = fxChronotrackApiConfigGet($intEveId);
if ($arrConfig === null) {
@ -1021,7 +1087,6 @@ function fxChronotrackApiSyncPushEvent($intEveId, $arrOptions = array()) {
$intPutOk = 0;
$intPostOk = 0;
$tabErrors = array();
$intBatchSize = MSIN_API_CHRONOTRACK_SYNC_BATCH_SIZE;
$tabCreates = array();
$tabCreatesMeta = array();
@ -1039,32 +1104,18 @@ function fxChronotrackApiSyncPushEvent($intEveId, $arrOptions = array()) {
}
}
for ($intBatchOff = 0; $intBatchOff < count($tabCreates); $intBatchOff += $intBatchSize) {
$tabSlice = array_slice($tabCreates, $intBatchOff, $intBatchSize);
$tabSliceMeta = array_slice($tabCreatesMeta, $intBatchOff, $intBatchSize);
$arrPost = fxChronotrackApiSyncPostEntries($intCtEventId, $tabSlice);
if ($arrPost['state'] === 'ok') {
$intOk += count($tabSlice);
$intPostOk += count($tabSlice);
continue;
}
$strErrMsg = $arrPost['message'] ?? 'Erreur POST entry';
foreach ($tabSlice as $intIdx => $arrEntry) {
$arrM = $tabSliceMeta[$intIdx];
$arrOne = fxChronotrackApiSyncPostEntries($intCtEventId, array($arrEntry));
if ($arrOne['state'] === 'ok') {
$intOk++;
$intPostOk++;
continue;
}
$intErr++;
$strOneErr = $arrOne['message'] ?? $strErrMsg;
if (count($tabErrors) < 8) {
$tabErrors[] = 'external_id=' . $arrM['external_id'] . ' — ' . $strOneErr;
}
fxChronotrackApiSyncLog($intEveId, $arrM['par_id'], 'push_entry', 'error',
'external_id=' . $arrM['external_id'] . ' — ' . $strOneErr);
}
// Créations + maj via POST lot (upsert) — découpage dichotomique si échec.
if (count($tabCreates) > 0) {
$arrRes = fxChronotrackApiSyncPostEntriesAdaptive(
$intCtEventId,
$tabCreates,
$tabErrors,
$intEveId,
$tabCreatesMeta
);
$intOk += $arrRes['ok'];
$intPostOk += $arrRes['ok'];
$intErr += $arrRes['err'];
}
if (count($tabUpdates) > 0) {
@ -1072,39 +1123,22 @@ function fxChronotrackApiSyncPushEvent($intEveId, $arrOptions = array()) {
foreach ($tabUpdates as $arrPayload) {
$tabUpdatesForPost[] = fxChronotrackApiSyncPayloadForPost($arrPayload);
}
for ($intBatchOff = 0; $intBatchOff < count($tabUpdatesForPost); $intBatchOff += $intBatchSize) {
$tabSlice = array_slice($tabUpdatesForPost, $intBatchOff, $intBatchSize);
$tabSliceMeta = array_slice($tabUpdatesMeta, $intBatchOff, $intBatchSize);
$tabSliceFull = array_slice($tabUpdates, $intBatchOff, $intBatchSize);
$arrPost = fxChronotrackApiSyncPostEntries($intCtEventId, $tabSlice);
if ($arrPost['state'] === 'ok') {
$intOk += count($tabSlice);
$intPostOk += count($tabSlice);
continue;
}
foreach ($tabSliceFull as $intIdx => $arrPayload) {
$arrM = $tabSliceMeta[$intIdx];
$arrOne = fxChronotrackApiSyncPushOneEntry($intCtEventId, $arrPayload);
if ($arrOne['state'] === 'ok') {
$intOk++;
if (($arrOne['method'] ?? '') === 'PUT') {
$intPutOk++;
} else {
$intPostOk++;
}
continue;
}
$intErr++;
$strOneErr = $arrOne['message'] ?? 'Erreur PUT/POST entry';
if (count($tabErrors) < 8) {
$tabErrors[] = 'external_id=' . $arrM['external_id'] . ' — ' . $strOneErr;
}
fxChronotrackApiSyncLog($intEveId, $arrM['par_id'], 'push_entry', 'error',
'external_id=' . $arrM['external_id'] . ' — ' . $strOneErr);
}
}
$arrRes = fxChronotrackApiSyncPostEntriesAdaptive(
$intCtEventId,
$tabUpdatesForPost,
$tabErrors,
$intEveId,
$tabUpdatesMeta
);
$intOk += $arrRes['ok'];
$intPostOk += $arrRes['ok'];
$intErr += $arrRes['err'];
}
// Si des MAJ restent en erreur (POST na pas pris le statut), tenter PUT unitaire
// uniquement pour ce petit sous-ensemble déjà en erreur — trop coûteux de re-PUT tout.
// Les erreurs sont déjà dans $tabErrors / logs.
fxChronotrackApiSyncLog(
$intEveId,
0,