flexbiz-server
Version:
Flexible Server
20 lines (19 loc) • 7.96 kB
JavaScript
/*
Prevent Closure Compiler rename this file */
const {AsyncLocalStorage}=require("node:async_hooks"),storage=new AsyncLocalStorage;exports.storage=storage;global.SESSION_STORE_MAP=new Map;exports.getCurrentStore=function(){return storage.getStore()};const SESSION_EXCLUDE_MODELS="log token trangthai trangthaiapp otp cache notification email tontucthoi listinfo reportinfo options labelinfo dmqddvt".split(" ");let globalStoreCounter=0,globalSessionCounter=0;
exports.runWithSession=async function($session$$,$fn$$){if(!$session$$)throw Error("Session kh\u00f4ng t\u1ed3n t\u1ea1i");if(exports.getCurrentStore())return $fn$$();const $storeId$$=++globalStoreCounter,$sessionId$$=$session$$?._debugId||`txn-${++globalSessionCounter}`;$session$$&&!$session$$._debugId&&($session$$._debugId=$sessionId$$);Logger.info(`[runWithSession] start storeId=${$storeId$$}, sessionId=${$sessionId$$}, ctrl=${$session$$?.ctrl_name}`);return storage.run({session:$session$$,storeId:$storeId$$,
sessionId:$sessionId$$},async()=>await $fn$$())};
exports.handlerWithSession=async function($handler$$,$ctrl$$,$req$$,$callback$$,...$extraArgs$$){let $attempt$$=0;for(;$attempt$$<3;){const $session$$=await mongoose.startSession();$session$$.ctrl_name=$ctrl$$.name;let $afterCommitCallbacks$$=[],$storeId_for_log$$="unknown";var $err_transactionResult$$=null;try{$err_transactionResult$$=await exports.runWithSession($session$$,()=>{const $label_time$$=`\u2705 Th\u1eddi gian ch\u1ea1y session ${$session$$._debugId}:`;console.time($label_time$$);$storeId_for_log$$=
exports.getCurrentStore()?.storeId||"unknown-store";Logger.info(`\ud83d\udd25 [handlerWithSession] Attempt ${$attempt$$+1} start storeId=${$storeId_for_log$$}, ctrl=${$ctrl$$.name}`);return new Promise(($resolve$$,$reject$$)=>{(async()=>{await $session$$.startTransaction();let $finished$$=!1;$handler$$($ctrl$$,$req$$,async($error$$,$result$$)=>{if(!$finished$$){$finished$$=!0;console.timeEnd($label_time$$);try{$error$$?(Logger.error("\u274c [handlerWithSession] error in handler, aborting...",$ctrl$$.name,
$error$$.message,$error$$?.errorLabels),setTimeout(async()=>{await $session$$.abortTransaction();$reject$$($error$$)},200)):($session$$&&$session$$.afterCommit&&($afterCommitCallbacks$$=[...$session$$.afterCommit]),Logger.info("\u2705 [handlerWithSession] committing...",$ctrl$$.name,", s\u1ed1 l\u01b0\u1ee3ng callback afterCommit:",$afterCommitCallbacks$$.length),await $session$$.commitTransaction(),$resolve$$($result$$))}catch($e$$){Logger.error("\u274c [handlerWithSession] error during commit/abort",
$e$$),await $session$$.abortTransaction().catch(()=>{}),$reject$$($e$$)}}},...$extraArgs$$)})()})});await $session$$.endSession();Logger.info("\u2705 [handlerWithSession] transaction committed, session closed");Logger.info(`\ud83d\udd25 [onAfterCommit] running ${$afterCommitCallbacks$$.length} callbacks for storeId=${$storeId_for_log$$}`);$afterCommitCallbacks$$.length>0&&await exports.runWithoutSession(async()=>{for(const $cb$$ of $afterCommitCallbacks$$)try{await $cb$$()}catch($err$$){Logger.error("\u274c [onAfterCommit error]",
$err$$)}});$callback$$(null,$err_transactionResult$$);return}catch($err$$){if(await $session$$.endSession().catch(()=>{}),Logger.warn("\u274c [handlerWithSession] transaction failed, session closed"),$attempt$$++,($err$$?.errorLabels?.includes("TransientTransactionError")||$err$$?.errorLabels?.includes("UnknownTransactionCommitResult")||$err$$?.code===112||$err$$?.message?.includes("Write conflict"))&&$attempt$$<3){const $delay$$=200*Math.pow(2,$attempt$$-1);Logger.warn(`\u26a0\ufe0f [handlerWithSession] Retry transaction (attempt ${$attempt$$}/${3}) after ${$delay$$}ms`);
await new Promise($res$$=>setTimeout($res$$,$delay$$))}else{Logger.error(`\u274c [handlerWithSession] Transaction failed permanently (${$ctrl$$.name})`,$err$$);$callback$$($err$$);return}}}$err_transactionResult$$=Error("Transaction failed after 3 retries");Logger.error(`\u274c [handlerWithSession] Max retries exceeded (${$ctrl$$.name})`);$callback$$($err_transactionResult$$)};
exports.executeInTransaction=async function($fn$$,$options$jscomp$2_parentSession_session$$={useParent:!1,forceSession:!1}){const {useParent:$useParent$$=!1,forceSession:$forceSession$$=!1}=$options$jscomp$2_parentSession_session$$;$options$jscomp$2_parentSession_session$$=exports.getCurrentSession();if($useParent$$&&$options$jscomp$2_parentSession_session$$&&!$options$jscomp$2_parentSession_session$$.hasEnded)return Logger.info(`\ud83d\udd17 [executeInTransaction] Join existing transaction ID=${$options$jscomp$2_parentSession_session$$._debugId||
$options$jscomp$2_parentSession_session$$.id.id}`),await $fn$$($options$jscomp$2_parentSession_session$$);$options$jscomp$2_parentSession_session$$=await mongoose.startSession();const $outerSessionId$$=`txn-auto-${++globalSessionCounter}`;$options$jscomp$2_parentSession_session$$._debugId=$outerSessionId$$;let $result$$=null,$committedCallbacks$$=[];try{await $options$jscomp$2_parentSession_session$$.withTransaction(async $sessionInTxn$$=>{$sessionInTxn$$.afterCommit=[];const $context$$={session:$sessionInTxn$$,
storeId:++globalStoreCounter,sessionId:$sessionInTxn$$._debugId||$outerSessionId$$,forceSession:$forceSession$$};await storage.run($context$$,async()=>{Logger.info(`\ud83d\udd04 [executeInTransaction] Start/Retry txnId=${$context$$.sessionId} storeId=${$context$$.storeId}`);$result$$=await $fn$$($sessionInTxn$$)});$sessionInTxn$$.afterCommit&&$sessionInTxn$$.afterCommit.length>0&&($committedCallbacks$$=[...$sessionInTxn$$.afterCommit])},{readPreference:"primary",readConcern:{level:"local"},writeConcern:{w:"majority"},
maxCommitTimeMS:5E3})}catch($error$$){const $isTransientError$$=$error$$.hasErrorLabel&&$error$$.hasErrorLabel("TransientTransactionError"),$isWriteConflict$$=$error$$.code===112;if($isTransientError$$||$isWriteConflict$$)throw Logger.error("\u274c[executeInTransaction] WriteConflict/Timeout after max retries:",$error$$),Error("D\u1eef li\u1ec7u n\u00e0y \u0111ang \u0111\u01b0\u1ee3c x\u1eed l\u00fd b\u1edfi ti\u1ebfn tr\u00ecnh kh\u00e1c. Vui l\u00f2ng th\u1eed l\u1ea1i sau.");Logger.error("\u274c[executeInTransaction] Failed permanently:",
$error$$);throw $error$$;}finally{await $options$jscomp$2_parentSession_session$$.endSession()}$committedCallbacks$$.length>0&&(Logger.info(`\ud83d\udd25 [executeInTransaction] Running ${$committedCallbacks$$.length} afterCommit callbacks`),exports.runWithoutSession(async()=>{for(const $cb$$ of $committedCallbacks$$)try{await $cb$$()}catch($err$$){Logger.error("\u274c [executeInTransaction] afterCommit error",$err$$)}}));return $result$$};
exports.onAfterCommit=async function($cb$$,$description$$="",$session$$=null,$store$$=null){$store$$=$store$$||storage.getStore();$session$$=$session$$||$store$$?.session;$store$$&&$session$$&&exports.isSessionActive($session$$)?($session$$.afterCommit=$session$$.afterCommit||[],$session$$.afterCommit.push($cb$$),$description$$&&Logger.info(`[onAfterCommit] added callback, storeId=${$store$$.storeId}, count=${$session$$.afterCommit.length},des=${$description$$}`)):($description$$&&Logger.info("[onAfterCommit] no active session, running immediately",
$description$$,", storeId=",$store$$?.storeId),await exports.runWithoutSession($cb$$))};exports.getAfterCommitList=function(){return exports.getCurrentSession()?.afterCommit||[]};exports.runWithoutSession=async function($fn$$){return storage.run({session:void 0},$fn$$)};exports.getCurrentSession=function(){return storage.getStore()?.session};
exports.isModelExcludedFromSession=function($model_name$$){$model_name$$=typeof $model_name$$==="string"?$model_name$$:$model_name$$?.modelName;return!(!$model_name$$||!SESSION_EXCLUDE_MODELS.includes($model_name$$))};exports.isSessionActive=function($session$$){if(!$session$$)return!1;try{return $session$$.inTransaction()&&!$session$$.hasEnded}catch{return!1}};Logger.info("[sessionContext] \u2705 Loaded");