Produced by Araxis Merge on 10/4/2017 8:04:33 AM Central Daylight Time. See www.araxis.com for information about Merge. This report uses XHTML and CSS2, and is best viewed with a modern standards-compliant browser. For optimum results when printing this report, use landscape orientation and enable printing of background images and colours in your browser.
| # | Location | File | Last Modified |
|---|---|---|---|
| 1 | rdk.zip\rdk\product\production\rdk\src\interceptors | synchronize.js | Mon Aug 28 19:41:48 2017 UTC |
| 2 | rdk.zip\rdk\product\production\rdk\src\interceptors | synchronize.js | Tue Oct 3 18:08:48 2017 UTC |
| Description | Between Files 1 and 2 |
|
|---|---|---|
| Text Blocks | Lines | |
| Unchanged | 6 | 1206 |
| Changed | 5 | 10 |
| Inserted | 0 | 0 |
| Removed | 0 | 0 |
| Whitespace | |
|---|---|
| Character case | Differences in character case are significant |
| Line endings | Differences in line endings (CR and LF characters) are ignored |
| CR/LF characters | Not shown in the comparison detail |
No regular expressions were active.
| 1 | 'use stric t'; | |
| 2 | ||
| 3 | let _ = re quire('lod ash'); | |
| 4 | let moment = require ('moment') ; | |
| 5 | ||
| 6 | let isPars edToPositi veInteger = require( '../utils/ integer-ch ecker').is ParsedToPo sitiveInte ger; | |
| 7 | ||
| 8 | ||
| 9 | // Perhaps a future version sh ould use t he jds-syn c-subsyste m.js | |
| 10 | // impleme ntation ra ther than including this here. | |
| 11 | const stan dardErrorR esponse = { | |
| 12 | status : 500, | |
| 13 | data: { | |
| 14 | er ror: { | |
| 15 | code: 50 0, | |
| 16 | message: 'There wa s an error processin g your req uest. The error has been logge d.' | |
| 17 | } | |
| 18 | } | |
| 19 | }; | |
| 20 | ||
| 21 | // Perhaps a future version sh ould use t he jds-syn c-subsyste m.js | |
| 22 | // impleme ntation ra ther than including this here. | |
| 23 | const noSi teResponse = { | |
| 24 | status : 404, | |
| 25 | data: { | |
| 26 | er ror: { | |
| 27 | code: 40 4, | |
| 28 | message: 'This pat ient\'s re cord is no t yet acce ssible. Pl ease try a gain in a few minute s. If it i s still no t accessib le, please contact y our HIMS r epresentat ive and ha ve the pat ient loade d into you r local Vi stA.' | |
| 29 | } | |
| 30 | } | |
| 31 | }; | |
| 32 | ||
| 33 | /* | |
| 34 | function i ntercept(r eq, res, n ext) | |
| 35 | ||
| 36 | For testin g purposes , you can inject a j dsSync ins tance in t he req par ameter: | |
| 37 | req.jdsSyn c = { // t est implem entation o bject }. | |
| 38 | ||
| 39 | To write a test harn ess, you m ust provid e the foll owing: | |
| 40 | ||
| 41 | req = { | |
| 42 | audit: {}, | |
| 43 | sessio n: { | |
| 44 | us er: { | |
| 45 | site: ' R E D A CTED ' // the ' mySite' va lue | |
| 46 | } | |
| 47 | }, | |
| 48 | interc eptors: { | |
| 49 | sy nchronize: { | |
| 50 | disabled : false | |
| 51 | } | |
| 52 | }, | |
| 53 | param: function( key) { | |
| 54 | if (key === ' pid') { | |
| 55 | return ' R E D A CTED ;3'; // th e pid of t he test pa tient | |
| 56 | } | |
| 57 | }, | |
| 58 | params : { | |
| 59 | pid: ' R E D A CTED ;3' // the pid of th e test pat ient | |
| 60 | }, | |
| 61 | logger : { | |
| 62 | tr ace: funct ion() {}, | |
| 63 | de bug: funct ion() {}, | |
| 64 | in fo: functi on() {}, | |
| 65 | wa rn: functi on() {}, | |
| 66 | er ror: funct ion() {}, | |
| 67 | fa tal: funct ion() {}, | |
| 68 | }, | |
| 69 | app: { | |
| 70 | co nfig: { | |
| 71 | resync: { | |
| 72 | inac tivityTime outMillis: 1000 * 60 * 60 * 24 , | |
| 73 | last SyncMaxInt ervalMilli s: 1000 * 60 * 10, | |
| 74 | erro rCooldownM inInterval Millis: 10 00 * 60 | |
| 75 | }, | |
| 76 | jdsSync: { | |
| 77 | sett ings: { | |
| 78 | waitMillis : 1000, | |
| 79 | timeoutMil lis: 1000 * 60 * 7, | |
| 80 | syncExists WaitDelayM illis: 100 0 * 30 | |
| 81 | } | |
| 82 | }, | |
| 83 | vxSyncSe rver: { | |
| 84 | baseUrl: ' http:// IP ' | |
| 85 | }, | |
| 86 | jdsServe r: { | |
| 87 | baseUrl: ' http:// IP ', | |
| 88 | urlL engthLimit : 120 | |
| 89 | } | |
| 90 | } | |
| 91 | }, | |
| 92 | jdsSyn c: { // Th ese are al l implemen ted in jds -sync-subs ystem.js | |
| 93 | ge tPatientSt atusSimple : function (pid, req, callback) {}, | |
| 94 | wa itForPatie ntLoad: fu nction(pid , mySite, req, callb ack) {}, | |
| 95 | cl earPatient : function (pid, req, callback) {}, | |
| 96 | lo adPatientP rioritized : function (pid, mySi te, req, c allback) { } | |
| 97 | } | |
| 98 | } | |
| 99 | ||
| 100 | res = { | |
| 101 | status : function (statusCod e) { | |
| 102 | re turn { | |
| 103 | rdkSend: function( response) {}; | |
| 104 | }; | |
| 105 | } | |
| 106 | } | |
| 107 | ||
| 108 | */ | |
| 109 | function i ntercept(r eq, res, n ext) { | |
| 110 | req.lo gger.debug ('synchron ize.interc ept()'); | |
| 111 | ||
| 112 | let co nfig = req .app.confi g; | |
| 113 | let lo gger = req .logger; | |
| 114 | ||
| 115 | let jd sSync = re q.jdsSync || _.get(r eq, ['app' , 'subsyst ems', 'jds Sync']); | |
| 116 | ||
| 117 | // Thi s is the " mySite" (i f any) | |
| 118 | let my Site = _.g et(req, [' session', 'user', 's ite'], nul l); | |
| 119 | ||
| 120 | // Thi s is the m aximum amo unt of tim e that is allowed to pass with out an upd ate | |
| 121 | // to a job stat us or meta stamp befo re the job is consid ered to ha ve stalled . | |
| 122 | let in activityTi meoutMilli s = config .resync.in activityTi meoutMilli s || 1000 * 60 * 60 * 24; | |
| 123 | ||
| 124 | // Thi s is the a mount of t ime betwee n calls to the sync endpoint. This is be cause | |
| 125 | // we don't want to call s ync every time, but we need to call it o ften enoug h to | |
| 126 | // ens ure that s econdary d ata can't get too st ale. VxSyn c doesn't duplicate sync | |
| 127 | // req uests (i.e . multiple sync requ ests on th e same pat ient at th e same tim e), | |
| 128 | // but too many calls clos e together can degra de perform ance. | |
| 129 | let la stSyncMaxI ntervalMil lis = conf ig.resync. lastSyncMa xIntervalM illis || 1 000 * 60 * 10; | |
| 130 | ||
| 131 | // Thi s is the m inimum amo unt of tim e that mus t pass bef ore the ex istence of a "hasErr or" | |
| 132 | // att ribute in the sync s tatus for "MySite" c auses a ne w sync. Er rors withi n less tha n than | |
| 133 | // tha t interval of time w ill cause the interc eptor to r eturn with the stand ard error response. | |
| 134 | let er rorCooldow nMinInterv alMillis = config.re sync.error CooldownMi nIntervalM illis || 1 000 * 60; | |
| 135 | if (is Intercepto rDisabled( config)) { | |
| 136 | lo gger.warn( 'synchroni ze.interce pt() inter ceptor dis abled'); | |
| 137 | re turn next( ); | |
| 138 | } | |
| 139 | ||
| 140 | // Not e: Strictl y speaking , this is not a 'pid ' the way VxSync def ines that term. | |
| 141 | // It is just a general 'p atient-ide ntifier'. | |
| 142 | let pi d = _.get( req, 'quer y.pid') || _.get(req , 'body.pi d') || _.g et(req, 'p arams.pid' ); | |
| 143 | ||
| 144 | if (!p id) { | |
| 145 | lo gger.debug ('synchron ize.interc ept() no " pid" query parameter , skip syn c'); | |
| 146 | re turn next( ); | |
| 147 | } | |
| 148 | ||
| 149 | // Syn chronizing a patient on an EDI PI or ICN type ident ifier mean s that the | |
| 150 | // syn c intercep tor will w ait for th e first si te to comp lete befor e returnin g. | |
| 151 | if (is Edipi(pid) || isIcn( pid)) { | |
| 152 | lo gger.debug ('synchron ize.interc ept() "pid " value wa s an EDIPI or ICN. W aiting for pid: [%s] sync on a t least on e site', p id); | |
| 153 | re turn waitF orFirstSit ePatientSy nc(logger, config, j dsSync, pi d, req, re s, next); | |
| 154 | } | |
| 155 | ||
| 156 | jdsSyn c.getPatie ntStatusSi mple(pid, req, funct ion(error, syncStatu s) { | |
| 157 | lo gger.trace ({ | |
| 158 | status: syncStatus | |
| 159 | }, `synchron ize.interc ept() call ed jdsSync .getPatien tStatusSim ple() for sync statu s check fo r pid: [${ pid}], myS ite: [${my Site}]`); | |
| 160 | lo gger.debug (`synchron ize.interc ept() call ed jdsSync .getPatien tStatusSim ple() for sync statu s check fo r pid: [${ pid}], myS ite: [${my Site}]`); | |
| 161 | ||
| 162 | // 1. on err or, next() | |
| 163 | lo gger.debug ('synchron ize.interc ept() 1. C heck for e rror retri eving simp le sync st atus for p id: [%s], mySite: [% s]', pid, mySite); | |
| 164 | if (error || _.isEmpty (syncStatu s) || _.is Empty(sync Status.dat a) || (syn cStatus.da ta.error & & syncStat us.data.er ror.code ! == 404)) { | |
| 165 | logger.w arn({ | |
| 166 | erro r: error | |
| 167 | }, `sync hronize.in tercept() 1a. Error retrieving simple sy nc status for pid: [ ${pid}], m ySite: [${ mySite}]; skipping`) ; | |
| 168 | return n ext(); | |
| 169 | } | |
| 170 | ||
| 171 | // 2. patien t not foun d, therefo re, it sho uld be syn chronized | |
| 172 | lo gger.info( 'synchroni ze.interce pt() 2. Ch eck for pa tient not found, syn chronizing pid: [%s] , mySite: [%s]', pid , mySite); | |
| 173 | if (syncStat us.data.er ror && syn cStatus.da ta.error.c ode === 40 4) { | |
| 174 | logger.i nfo('synch ronize.int ercept() 2 a. Patient not found , synchron izing pid: [%s], myS ite: [%s]' , pid, myS ite); | |
| 175 | return s yncPatient (config, l ogger, jds Sync, pid, mySite, r eq, res, n ext); | |
| 176 | } | |
| 177 | ||
| 178 | // 3. if syn c for mySi te is comp lete, chec k to be su re that sy nc() doesn 't need to be called | |
| 179 | lo gger.debug ('synchron ize.interc ept() 3. c heck if pa tient pid: [%s], myS ite: [%s] is synced, but excee ds timeout ', pid, my Site); | |
| 180 | le t mySiteSy nchComplet e = _.get( syncStatus , ['data', 'sites', mySite, 's yncComplet ed']); | |
| 181 | if (mySiteSy nchComplet e) { | |
| 182 | if (isSy ncLastUpda teTimeoutE xceeded(sy ncStatus.d ata, lastS yncMaxInte rvalMillis )) { | |
| 183 | logg er.trace(s yncStatus, 'synchron ize.interc ept() 3a. Patient pi d: [%s], m ySite: [%s ] synced, but exceed ed timeout , resyncin g patient' , pid, myS ite); | |
| 184 | logg er.info('s ynchronize .intercept () 3a. Pat ient pid: [%s], mySi te: [%s] s ynced, but exceeded timeout, r esyncing p atient', p id, mySite ); | |
| 185 | retu rn syncPat ient(confi g, logger, jdsSync, pid, mySit e, req, re s, next); | |
| 186 | } | |
| 187 | ||
| 188 | logger.i nfo('synch ronize.int ercept() 3 b. Patient pid: [%s] , mySite: [%s] is sy nced and s yncPatient () does no t need to be called' , pid, myS ite); | |
| 189 | return n ext(); | |
| 190 | } | |
| 191 | ||
| 192 | // 4. if lat estEnterpr iseSyncReq uestTimest amp is emp ty, clear and resync | |
| 193 | // Failing t o clear th e patient first can result in the VistA data not b eing synce d. | |
| 194 | // This cond ition can happen whe n all of a patient's job histo ry is dele ted. Even | |
| 195 | // though th e patient sync was c omplete, r emoving th e job hist ory will c ause the | |
| 196 | // latestEnt erpriseSyn cRequestTi mestamp fi eld to con tain an em pty string (and the | |
| 197 | // sync stat us to be i ncomplete) . | |
| 198 | lo gger.debug ('jds-sync -subsystem .waitForPa tientLoad( ) 4. check SimpleStat us() check pid: [%s] , priority Site: [%s] , latestEn terpriseSy ncRequestT imestamp: [%s] is an integer', pid, mySi te, syncSt atus.data. latestEnte rpriseSync RequestTim estamp); | |
| 199 | if (!isParse dToPositiv eInteger(s yncStatus. data.lates tEnterpris eSyncReque stTimestam p)) { | |
| 200 | logger.i nfo('synch ronize.int ercept() 4 a. latestE nterpriseS yncRequest Timestamp: [%s] is no t an integ er, cleari ng and res yncing pid : [%s], my Site: [%s] ', syncSta tus.data.l atestEnter priseSyncR equestTime stamp, pid , mySite); | |
| 201 | return c learThenSy ncPatient( config, lo gger, jdsS ync, pid, mySite, re q, res, ne xt); | |
| 202 | } | |
| 203 | ||
| 204 | // 5. if the re is an e rror in th e sync sta tus for my Site, chec k to sync again or j ust return an error | |
| 205 | lo gger.info( 'synchroni ze.interce pt() 5. Ch eck for er ror found in site [% s] sync st atus for p id: [%s]', mySite, p id); | |
| 206 | le t errorInS ite = _.ge t(syncStat us, ['data ', 'sites' , mySite, 'hasError' ], false); | |
| 207 | if (errorInS ite) { | |
| 208 | if (isEr rorCooldow nTimeoutEx ceeded(syn cStatus.da ta, errorC ooldownMin IntervalMi llis)) { | |
| 209 | logg er.info('s ynchronize .intercept () 5a. An error foun d in site [%s] for p id: [%s], cooldown e xceeded, r esyncing p atient', m ySite, pid ); | |
| 210 | retu rn syncPat ient(confi g, logger, jdsSync, pid, mySit e, req, re s, next); | |
| 211 | } | |
| 212 | ||
| 213 | logger.i nfo('synch ronize.int ercept() 5 b. An erro r found in site [%s] for pid: [%s], cool down excee ded, retur ning error message', mySite, p id); | |
| 214 | return r es.status( 500).rdkSe nd('There was an err or process ing your r equest. Th e error ha s been log ged.'); | |
| 215 | } | |
| 216 | ||
| 217 | // 6. if the sync has been inact ive too lo ng, clearA ndSync() | |
| 218 | lo gger.info( 'synchroni ze.interce pt() 6. Ch eck if the activity timeout wa s exceeded and patie nt should be cleared and resyn ced pid: [ %s], mySit e: [%s]', pid, mySit e); | |
| 219 | if (!syncSta tus.data.s yncComplet ed && isSy ncLastUpda teTimeoutE xceeded(sy ncStatus.d ata, inact ivityTimeo utMillis)) { | |
| 220 | logger.i nfo('synch ronize.int ercept() 6 a. The act ivity time out was ex ceeded, cl earing and resyncing pid: [%s] , mySite: [%s]', pid , mySite); | |
| 221 | return c learThenSy ncPatient( config, lo gger, jdsS ync, pid, mySite, re q, res, ne xt); | |
| 222 | } | |
| 223 | ||
| 224 | // 7. if the sync for mySite is not comple te and syn c is not " stuck", wa it for syn c on mySit e to compl ete | |
| 225 | lo gger.info( 'synchroni ze.interce pt() 7a. C heck if pa tient pid: [%s], myS ite: [%s] sync in pr ogress nor mally and sync inter ceptor sho uld contin ue to wait ', pid, my Site); | |
| 226 | if (!mySiteS ynchComple te && !isS yncLastUpd ateTimeout Exceeded(s yncStatus. data, inac tivityTime outMillis) ) { | |
| 227 | logger.i nfo('synch ronize.int ercept() 7 a. Patient pid: [%s] , mySite: [%s] sync already in progress- -awaiting completion ', pid, my Site); | |
| 228 | return w aitForPati entSync(co nfig, logg er, jdsSyn c, pid, my Site, req, res, next ); | |
| 229 | } | |
| 230 | ||
| 231 | // 8. In all other cas es, sync t he patient (note: th is will us e 'mySite' to determ ine comple tion) | |
| 232 | lo gger.trace (syncStatu s, 'synchr onize.inte rcept() 8. Calling s ync for pi d: [%s], m ySite: [%s ]', pid, m ySite); | |
| 233 | lo gger.info( 'synchroni ze.interce pt() 8. Ca lling sync for pid: [%s], mySi te: [%s]', pid, mySi te); | |
| 234 | sy ncPatient( config, lo gger, jdsS ync, pid, mySite, re q, res, ne xt); | |
| 235 | }); | |
| 236 | } | |
| 237 | ||
| 238 | ||
| 239 | function w aitForPati entSync(co nfig, logg er, jdsSyn c, pid, my Site, req, res, next ) { | |
| 240 | logger .debug('sy nchronize. waitForPat ientSync() waiting f or pid: [% s], mySite : [%s]', p id, mySite ); | |
| 241 | ||
| 242 | jdsSyn c.waitForP atientLoad (pid, mySi te, req, f unction(er ror, resul t) { | |
| 243 | lo gger.debug ('synchron ize.waitFo rPatientSy nc() start sync wait callback for pid: [ %s], mySit e: [%s]', pid, mySit e); | |
| 244 | if (error) { | |
| 245 | let stat us = _.isN umber(erro r) ? error : 500; | |
| 246 | return r es.status( status).rd kSend(resu lt || erro r); | |
| 247 | } | |
| 248 | ||
| 249 | ne xt(); | |
| 250 | }); | |
| 251 | } | |
| 252 | ||
| 253 | function c learThenSy ncPatient( config, lo gger, jdsS ync, pid, mySite, re q, res, ne xt) { | |
| 254 | logger .debug('sy nchronize. clearThenS yncPatient () Clearin g, then sy nchronizin g pid: [%s ], mySite: [%s]', pi d, mySite) ; | |
| 255 | ||
| 256 | jdsSyn c.clearPat ient(pid, req, funct ion(error, result) { | |
| 257 | lo gger.debug ('synchron ize.clearT henSyncPat ient() sta rt syncCle ar callbac k for pid: [%s], myS ite: [%s]' , pid, myS ite); | |
| 258 | if (error) { | |
| 259 | let stat us = _.isN umber(erro r) ? error : 500; | |
| 260 | result = result || error; | |
| 261 | return r es.status( status).rd kSend(resu lt); | |
| 262 | } | |
| 263 | ||
| 264 | sy ncPatient( config, lo gger, jdsS ync, pid, mySite, re q, res, ne xt); | |
| 265 | }); | |
| 266 | } | |
| 267 | ||
| 268 | function s yncPatient (config, l ogger, jds Sync, pid, mySite, r eq, res, n ext) { | |
| 269 | logger .debug('sy nchronize. syncPatien t() Synchr onizing pi d: [%s], m ySite: [%s ]', pid, m ySite); | |
| 270 | ||
| 271 | jdsSyn c.loadPati entPriorit ized(pid, mySite, re q, functio n(error, r esult) { | |
| 272 | lo gger.debug ('synchron ize.syncPa tient() ca lled jdsSy nc.loadPat ientPriori tized() fo r pid: [%s ], mySite: [%s]', pi d, mySite) ; | |
| 273 | if (error) { | |
| 274 | if (erro r === 404) { | |
| 275 | logg er.debug(' synchroniz e.syncPati ent() 404 syncLoad f or pid: [% s], mySite : [%s]', p id, mySite ); | |
| 276 | retu rn res.sta tus(404).r dkSend(noS iteRespons e); | |
| 277 | } | |
| 278 | ||
| 279 | logger.e rror('sync hronize.sy ncPatient( ) Error sy nchronizin g pid: [%s ], mySite: [%s]', pi d, mySite) ; | |
| 280 | logger.e rror('sync hronize.sy ncPatient( ) %j', err or); | |
| 281 | return r es.status( 500).rdkSe nd('There was an err or process ing your r equest. Th e error ha s been log ged.'); | |
| 282 | } | |
| 283 | ||
| 284 | if (!result) { | |
| 285 | logger.e rror('sync hronize.sy ncPatient( ) Empty re sponse fro m sync sub system for pid: [%s] , mySite: [%s]', pid , mySite); | |
| 286 | return r es.status( 500).rdkSe nd('There was an err or process ing your r equest. Th e error ha s been log ged.'); | |
| 287 | } | |
| 288 | ||
| 289 | if (!_.has(r esult, 'da ta') || re sult.statu s === 500) { | |
| 290 | logger.e rror('sync hronize.sy ncPatient( ) Error re sponse fro m sync sub system for `pid: [%s ], mySite: [%s]`', p id, mySite ); | |
| 291 | logger.e rror('sync hronize.sy ncPatient( ) %j', res ult); | |
| 292 | ||
| 293 | return n ext(); | |
| 294 | } | |
| 295 | ||
| 296 | if (result.s tatus === 404) { | |
| 297 | logger.d ebug('sync hronize.sy ncPatient( ) 404 sync Load for p id: [%s], mySite: [% s]', pid, mySite); | |
| 298 | return r es.status( result.sta tus).rdkSe nd(result) ; | |
| 299 | } | |
| 300 | ||
| 301 | lo gger.trace (result); | |
| 302 | ||
| 303 | lo gger.debug ('synchron ize.syncPa tient() sy ncLoad for pid: [%s] , mySite: [%s] - con tinue', pi d, mySite) ; | |
| 304 | ne xt(); | |
| 305 | }); | |
| 306 | } | |
| 307 | ||
| 308 | ||
| 309 | /* | |
| 310 | Variadic F unction | |
| 311 | function w aitForFirs tSitePatie ntSync(log ger, confi g, pid, re q, res, ne xt, startT ime) | |
| 312 | function w aitForFirs tSitePatie ntSync(log ger, confi g, pid, re q, res, ne xt) | |
| 313 | ||
| 314 | startTime: not inclu ded in the initial r ecursive c all | |
| 315 | */ | |
| 316 | function w aitForFirs tSitePatie ntSync(log ger, confi g, jdsSync , pid, req , res, nex t, startTi me) { | |
| 317 | logger .debug('sy nchronize. waitForFir stSitePati entSync() pid: [%s]' , pid); | |
| 318 | ||
| 319 | jdsSyn c.getPatie ntStatusSi mple(pid, req, funct ion(error, syncStatu s) { | |
| 320 | lo gger.trace ({ | |
| 321 | status: syncStatus | |
| 322 | }, `synchron ize.waitFo rFirstSite PatientSyn c() called jdsSync.g etPatientS tatusSimpl e() for pi d: [${pid} ] for firs t site`); | |
| 323 | ||
| 324 | // 1. error returned i n callback | |
| 325 | lo gger.debug ('synchron ize.waitFo rFirstSite PatientSyn c() 1. Che ck for err or retriev ing simple sync stat us for pid : [%s]', p id); | |
| 326 | if (error || _.isEmpty (syncStatu s) || _.is Empty(sync Status.dat a) || (syn cStatus.da ta.error & & syncStat us.data.er ror.code ! == 404)) { | |
| 327 | logger.w arn({ | |
| 328 | erro r: error | |
| 329 | }, `sync hronize.wa itForFirst SitePatien tSync() 1a . Error re trieving s imple sync status fo r pid: [${ pid}], so skipping`) ; | |
| 330 | return n ext(); | |
| 331 | } | |
| 332 | ||
| 333 | le t now = Da te.now(); | |
| 334 | le t loopDela yMillis = config.jds Sync.setti ngs.waitMi llis; | |
| 335 | le t syncTime outMillis = config.j dsSync.set tings.time outMillis; | |
| 336 | le t syncExis tsWaitDela yMillis = config.jds Sync.setti ngs.syncEx istsWaitDe layMillis; | |
| 337 | ||
| 338 | // if sync h as already started, try to use the earli est timest amp/stampT ime for th e | |
| 339 | // sync time out calcul ation. Oth erwise use the curre nt time. N ote that t his should | |
| 340 | // only be r elevant to the first invocatio n of waitF orFirstSit ePatientSy nc() in th e | |
| 341 | // recursive call stac k. | |
| 342 | st artTime = startTime || minMome nt([new Da te(), | |
| 343 | syncStat us.data.la testEnterp riseSyncRe questTimes tamp, | |
| 344 | syncStat us.data.la testJobTim estamp, | |
| 345 | moment(s yncStatus. data.lates tSourceSta mpTime, 'Y YYYMMDDHHm mss') | |
| 346 | ]) .valueOf() ; | |
| 347 | ||
| 348 | lo gger.debug ('synchron ize.waitFo rFirstSite PatientSyn c() pid: [ %s] loopDe layMillis= %s syncTim eoutMillis =%s syncEx istsWaitDe layMillis= %s', pid, loopDelayM illis, syn cTimeoutMi llis, sync ExistsWait DelayMilli s); | |
| 349 | ||
| 350 | // 2. 404 an d 404-time out exceed ed: res.se nd(result. status, re sult.data) | |
| 351 | lo gger.debug ('synchron ize.waitFo rFirstSite PatientSyn c() 2. Che ck for pat ient not f ound, pid: [%s]', pi d); | |
| 352 | if (syncStat us.data.er ror && syn cStatus.da ta.error.c ode === 40 4) { | |
| 353 | if (isSy ncExistsDe layAtTimeo ut(startTi me, syncEx istsWaitDe layMillis) ) { | |
| 354 | logg er.warn('s ynchronize .waitForFi rstSitePat ientSync() 2a. Patie nt Sync fo r pid: [%s ], timeout waiting t o get past 404 statu s', pid); | |
| 355 | retu rn res.sta tus(404).r dkSend(noS iteRespons e); | |
| 356 | } | |
| 357 | ||
| 358 | logger.i nfo('synch ronize.wai tForFirstS itePatient Sync() 2b. Patient s ync for [% s] returne d 404, con tinuing to wait', pi d); | |
| 359 | return s etTimeout( waitForFir stSitePati entSync, l oopDelayMi llis, logg er, config , jdsSync, pid, req, res, next , startTim e); | |
| 360 | } | |
| 361 | ||
| 362 | // 3. Patien t Sync com plete: nex t() | |
| 363 | lo gger.info( 'synchroni ze.waitFor FirstSiteP atientSync () 3. Chec k if sync complete f or at leas t one site for pid: [%s]', pid ); | |
| 364 | if (isOneSit eCompleted (syncStatu s)) { | |
| 365 | logger.i nfo('synch ronize.wai tForFirstS itePatient Sync() 3a. Sync comp lete for a t least on e site for pid: [%s] ', pid); | |
| 366 | return n ext(); | |
| 367 | } | |
| 368 | ||
| 369 | // 4. if lat estEnterpr iseSyncReq uestTimest amp is emp ty, this w ill not re solve, so return an error | |
| 370 | // This cond ition can happen whe n all of a patient's job histo ry is dele ted. Even | |
| 371 | // though th e patient sync was c omplete, r emoving th e job hist ory will c ause the | |
| 372 | // latestEnt erpriseSyn cRequestTi mestamp fi eld to con tain an em pty string (and the | |
| 373 | // sync stat us to be i ncomplete) . | |
| 374 | lo gger.debug ('synchron ize.waitFo rFirstSite PatientSyn c() 4. pid : [%s], la testEnterp riseSyncRe questTimes tamp: [%s] ', pid, sy ncStatus.d ata.latest Enterprise SyncReques tTimestamp ); | |
| 375 | if (!isParse dToPositiv eInteger(s yncStatus. data.lates tEnterpris eSyncReque stTimestam p)) { | |
| 376 | logger.e rror('sync hronize.wa itForFirst SitePatien tSync() 4a . checkSim pleStatus( ) pid: [%s ], latestE nterpriseS yncRequest Timestamp: [%s] is n ot an Inte ger', pid, syncStatu s.data.lat estEnterpr iseSyncReq uestTimest amp); | |
| 377 | return r es.status( 500).rdkSe nd(standar dErrorResp onse); | |
| 378 | } | |
| 379 | ||
| 380 | // 5. sync t imeout exc eeded befo re at leas t one site completed : return s tandardErr orResponse | |
| 381 | lo gger.info( 'synchroni ze.waitFor FirstSiteP atientSync () 5. Chec k for time out while waiting fo r at least one site to complet e for sync on pid: [ %s]', pid) ; | |
| 382 | if (now - st artTime > syncTimeou tMillis) { | |
| 383 | logger.w arn('synch ronize.wai tForFirstS itePatient Sync() 5a. Timeout w aiting for at least one site t o complete for sync on pid: [% s]', pid); | |
| 384 | return r es.status( 500).rdkSe nd(standar dErrorResp onse); | |
| 385 | } | |
| 386 | ||
| 387 | // 6. All si tes are in Sync/Job error | |
| 388 | lo gger.info( 'synchroni ze.waitFor FirstSiteP atientSync () 6. Chec k if sync had an err or every s ite status for pid: [%s]', pid ); | |
| 389 | if (isEveryS iteInError (syncStatu s)) { | |
| 390 | logger.w arn('synch ronize.wai tForFirstS itePatient Sync() 6a. Sync had an error e very site status for pid: [%s] ', pid); | |
| 391 | return r es.status( 500).rdkSe nd(standar dErrorResp onse); | |
| 392 | } | |
| 393 | ||
| 394 | // 7. everyt hing else: wait and test again | |
| 395 | lo gger.info( 'synchroni ze.waitFor FirstSiteP atientSync () 7. Pati ent sync f or [%s] no t yet comp lete for a t least on e site, co ntinuing t o wait', p id); | |
| 396 | re turn setTi meout(wait ForFirstSi tePatientS ync, loopD elayMillis , logger, config, jd sSync, pid , req, res , next, st artTime); | |
| 397 | }); | |
| 398 | } | |
| 399 | ||
| 400 | ||
| 401 | function i sOneSiteCo mpleted(si mpleSyncSt atus) { | |
| 402 | let da ta = _.get (simpleSyn cStatus, ' data', {}) ; | |
| 403 | ||
| 404 | if (da ta.syncCom pleted) { | |
| 405 | re turn true; | |
| 406 | } | |
| 407 | ||
| 408 | return _.some(da ta.sites, function(s ite) { | |
| 409 | re turn site. syncComple ted; | |
| 410 | }); | |
| 411 | } | |
| 412 | ||
| 413 | function i sEverySite InError(si mpleSyncSt atus) { | |
| 414 | let da ta = _.get (simpleSyn cStatus, ' data', {}) ; | |
| 415 | ||
| 416 | if (_. isEmpty(da ta.sites)) { | |
| 417 | re turn false ; | |
| 418 | } | |
| 419 | ||
| 420 | return _.every(d ata.sites, function( site) { | |
| 421 | re turn site. hasError; | |
| 422 | }); | |
| 423 | } | |
| 424 | ||
| 425 | ||
| 426 | function i sIntercept orDisabled (config) { | |
| 427 | return _.has(con fig, 'inte rceptors') && _.has( config.int erceptors, 'synchron ize') && c onfig.inte rceptors.s ynchronize .disabled === true; | |
| 428 | } | |
| 429 | ||
| 430 | function i sPid(id) { | |
| 431 | return !_.isEmpt y(id) && / ^[0-9a-fA- F]{4};[0-9 ]+$/.test( id); | |
| 432 | } | |
| 433 | ||
| 434 | function i sIcn(id) { | |
| 435 | return !_.isEmpt y(id) && / \w+V\w+/.t est(id); | |
| 436 | } | |
| 437 | ||
| 438 | function i sEdipi(id) { | |
| 439 | return !_.isEmpt y(id) && / ^DOD;\d+/. test(id); | |
| 440 | } | |
| 441 | ||
| 442 | ||
| 443 | /* | |
| 444 | Returns th e earliest moment or undefined if the it ems in the moments a rray | |
| 445 | are not va lid Date/t imestamp/m oment obje cts. Note the value returned i s a | |
| 446 | moment obj ect. | |
| 447 | */ | |
| 448 | function m inMoment(m oments) { | |
| 449 | return fetchMome ntByCriter ium(moment .prototype .isBefore, moments); | |
| 450 | } | |
| 451 | ||
| 452 | ||
| 453 | /* | |
| 454 | Returns th e earliest moment or undefined if the it ems in the moments a rray | |
| 455 | are not va lid Date/t imestamp/m oment obje cts. Note the value returned i s a | |
| 456 | moment obj ect. | |
| 457 | */ | |
| 458 | function m axMoment(m oments) { | |
| 459 | return fetchMome ntByCriter ium(moment .prototype .isAfter, moments); | |
| 460 | } | |
| 461 | ||
| 462 | ||
| 463 | /* | |
| 464 | Returns th e last mom ent that p asses the func test or undefin ed if the | |
| 465 | items in t he moments array are not valid Date/time stamp/mome nt objects . | |
| 466 | Note the v alue retur ned is a m oment obje ct. | |
| 467 | */ | |
| 468 | function f etchMoment ByCriteriu m(func, mo ments) { | |
| 469 | if (_. isUndefine d(moments) || _.isNu ll(moments )) { | |
| 470 | re turn; | |
| 471 | } | |
| 472 | ||
| 473 | moment s = !_.isA rray(momen ts) ? [mom ents] : mo ments; | |
| 474 | let va lue; | |
| 475 | ||
| 476 | _.each (moments, function(m omentObj) { | |
| 477 | if (moment.i sDate(mome ntObj) || _.isNumber (momentObj )) { | |
| 478 | momentOb j = moment (momentObj ); | |
| 479 | } | |
| 480 | ||
| 481 | if (moment.i sMoment(mo mentObj) & & momentOb j.isValid( ) && (_.is Undefined( value) || func.call( momentObj, value))) { | |
| 482 | value = momentObj; | |
| 483 | } | |
| 484 | }); | |
| 485 | ||
| 486 | return value; | |
| 487 | } | |
| 488 | ||
| 489 | /* | |
| 490 | Variadic F unction: | |
| 491 | function i sSyncExist sDelayAtTi meout(star tTime, syn cExistsWai tDelayMill is, now) { | |
| 492 | function i sSyncExist sDelayAtTi meout(star tTime, syn cExistsWai tDelayMill is) { | |
| 493 | ||
| 494 | startTime: a millise cond times tamp value similar t o what is returned b y Date.now () | |
| 495 | ||
| 496 | syncExists WaitDelayM illis: a m illisecond value. | |
| 497 | ||
| 498 | now: a mil lisecond t imestamp v alue simil ar to what is return ed by Date .now() | |
| 499 | If now is not includ ed or is n ot a numbe r, this fu nction wil l generate a value | |
| 500 | using Date .now() | |
| 501 | */ | |
| 502 | function i sSyncExist sDelayAtTi meout(star tTime, syn cExistsWai tDelayMill is, now) { | |
| 503 | if (!_ .isNumber( now)) { | |
| 504 | no w = Date.n ow(); | |
| 505 | } | |
| 506 | ||
| 507 | return now - sta rtTime > s yncExistsW aitDelayMi llis; | |
| 508 | } | |
| 509 | ||
| 510 | /* | |
| 511 | Variadic F unction: | |
| 512 | function i sSyncLastU pdateTimeo utExceeded (status, i nactivityT imeoutMill is, now) | |
| 513 | function i sSyncLastU pdateTimeo utExceeded (status, i nactivityT imeoutMill is) | |
| 514 | ||
| 515 | This funct ion checks an all-si tes simple patient s ync status to determ ine | |
| 516 | if the syn c has "sta lled". The sync is c onsidered to have st alled if t he | |
| 517 | interval b etween now and the l ast time u pdate (i.e . the late st value o f | |
| 518 | all of the non-site time value s: job tim estamp and metaStamp Time) exce eds | |
| 519 | the value of 'inacti vityTimeou tMills'. | |
| 520 | ||
| 521 | status: Th is should be a gener al simple patient sy nc status (i.e. not site-speci fic). | |
| 522 | ||
| 523 | now: This should be either a n umber valu e (e.g. Da te().getTi me()) or a Date obje ct. | |
| 524 | In any oth er instanc e, the val ue of now will be th e current date/time. | |
| 525 | */ | |
| 526 | function i sSyncLastU pdateTimeo utExceeded (status, i nactivityT imeoutMill is, now) { | |
| 527 | if (_. isEmpty(st atus)) { | |
| 528 | re turn false ; | |
| 529 | } | |
| 530 | ||
| 531 | let la testEnterp riseSyncRe questTimes tamp = mom ent(status .latestEnt erpriseSyn cRequestTi mestamp); | |
| 532 | let la testJobTim estamp = m oment(stat us.latestJ obTimestam p); | |
| 533 | let la testSource StampTime = moment(s tatus.late stSourceSt ampTime, ' YYYYMMDDHH mmss'); | |
| 534 | ||
| 535 | let la testUpdate Time = max Moment([la testEnterp riseSyncRe questTimes tamp, late stJobTimes tamp, late stSourceSt ampTime]); | |
| 536 | ||
| 537 | if (!l atestUpdat eTime) { | |
| 538 | re turn false ; | |
| 539 | } | |
| 540 | ||
| 541 | if (mo ment.isDat e(now) || _.isNumber (now)) { | |
| 542 | no w = moment (now); | |
| 543 | } else { | |
| 544 | no w = moment (); | |
| 545 | } | |
| 546 | ||
| 547 | // dea dline is t he latest time for t he last up date witho ut the | |
| 548 | // int erceptor c onsidering the patie nt sync to have stal led. | |
| 549 | let de adline = n ow.subtrac t(inactivi tyTimeoutM illis, 'mi lliseconds '); | |
| 550 | ||
| 551 | return latestUpd ateTime.is Before(dea dline); | |
| 552 | } | |
| 553 | ||
| 554 | /* | |
| 555 | Variadic F unction: | |
| 556 | function i sErrorCool downTimeou tExceeded( status, er rorCooldow nMinInterv alMillis, now) | |
| 557 | function i sErrorCool downTimeou tExceeded( status, er rorCooldow nMinInterv alMillis) | |
| 558 | ||
| 559 | This funct ion checks a simple patient sy nc status to determi ne if the cooldown p eriod | |
| 560 | since the sync was s tarted has passed. | |
| 561 | ||
| 562 | status: Th is should be a simpl e patient sync statu s. | |
| 563 | ||
| 564 | now: This should be either a n umber valu e (e.g. Da te().getTi me()) or a Date obje ct. | |
| 565 | In any oth er instanc e, the val ue of now will be th e current date/time. | |
| 566 | */ | |
| 567 | function i sErrorCool downTimeou tExceeded( status, er rorCooldow nMinInterv alMillis, now) { | |
| 568 | if (_. isEmpty(st atus)) { | |
| 569 | re turn false ; | |
| 570 | } | |
| 571 | ||
| 572 | let la testEnterp riseSyncRe questTimes tamp = mom ent(status .latestEnt erpriseSyn cRequestTi mestamp); | |
| 573 | ||
| 574 | if (la testEnterp riseSyncRe questTimes tamp < 1) { | |
| 575 | re turn false ; | |
| 576 | } | |
| 577 | ||
| 578 | if (mo ment.isDat e(now) || _.isNumber (now)) { | |
| 579 | no w = moment (now); | |
| 580 | } else { | |
| 581 | no w = moment (); | |
| 582 | } | |
| 583 | ||
| 584 | // dea dline is t he latest time for t he last up date witho ut the | |
| 585 | // int erceptor c onsidering the patie nt sync to have stal led. | |
| 586 | let de adline = n ow.subtrac t(errorCoo ldownMinIn tervalMill is, 'milli seconds'); | |
| 587 | ||
| 588 | return latestEnt erpriseSyn cRequestTi mestamp.is Before(dea dline); | |
| 589 | } | |
| 590 | ||
| 591 | ||
| 592 | module.exp orts = int ercept; | |
| 593 | intercept. _isSyncLas tUpdateTim eoutExceed ed = isSyn cLastUpdat eTimeoutEx ceeded; | |
| 594 | intercept. _isErrorCo oldownTime outExceede d = isErro rCooldownT imeoutExce eded; | |
| 595 | intercept. _isInterce ptorDisabl ed = isInt erceptorDi sabled; | |
| 596 | intercept. _maxMoment = maxMome nt; | |
| 597 | intercept. _minMoment = minMome nt; | |
| 598 | intercept. _isPid = i sPid; | |
| 599 | intercept. _isIcn = i sIcn; | |
| 600 | intercept. _isEdipi = isEdipi; | |
| 601 | intercept. _clearThen SyncPatien t = clearT henSyncPat ient; | |
| 602 | intercept. _syncPatie nt = syncP atient; | |
| 603 | intercept. _waitForFi rstSitePat ientSync = waitForFi rstSitePat ientSync; | |
| 604 | intercept. _isSyncExi stsDelayAt Timeout = isSyncExis tsDelayAtT imeout; | |
| 605 | intercept. _isOneSite Completed = isOneSit eCompleted ; | |
| 606 | intercept. _isEverySi teInError = isEveryS iteInError ; | |
| 607 | intercept. _standardE rrorRespon se = stand ardErrorRe sponse; | |
| 608 | intercept. _noSiteRes ponse = no SiteRespon se; |
Araxis Merge (but not the data content of this report) is Copyright © 1993-2016 Araxis Ltd (www.araxis.com). All rights reserved.