()
| 210 | } |
| 211 | |
| 212 | const heartBeat = async () => { |
| 213 | // ignore milliseconds so the comparison against the matched slot is exact. |
| 214 | const currentDate = nowWithoutMs(); |
| 215 | |
| 216 | const plan = planBeat( |
| 217 | expectedNextExecution, |
| 218 | currentDate, |
| 219 | this.missedExecutionTolerance, |
| 220 | (date: Date) => this.timeMatcher.getNextMatch(date) |
| 221 | ); |
| 222 | |
| 223 | expectedNextExecution = plan.next; |
| 224 | |
| 225 | // Report every superseded slot. The "missed execution" warning is emitted |
| 226 | // by the task's onMissedExecution handler so it can honour listener-based |
| 227 | // and explicit suppression and use the task's logger. |
| 228 | for (const missedSlot of plan.missed) { |
| 229 | runAsync(this.onMissedExecution, missedSlot, this.onErrorFallback); |
| 230 | } |
| 231 | |
| 232 | if (plan.run) { |
| 233 | // overlap prevention |
| 234 | if (lastExecution && lastExecution.getState() === 'pending') { |
| 235 | runAsync(this.onOverlap, plan.run, this.onErrorFallback); |
| 236 | if (this.noOverlap) { |
| 237 | this.logger.warn('task still running, new execution blocked by overlap prevention!'); |
| 238 | armHeartBeat(); |
| 239 | return; |
| 240 | } |
| 241 | } |
| 242 | |
| 243 | const slot = plan.run; |
| 244 | lastExecution = new TrackedPromise(async (resolve, reject) => { |
| 245 | try { |
| 246 | await this.runCoordinated(slot, () => runTask(slot)); |
| 247 | resolve(true); |
| 248 | } catch (err) { |
| 249 | reject(err); |
| 250 | } |
| 251 | }); |
| 252 | } |
| 253 | |
| 254 | armHeartBeat(); |
| 255 | } |
| 256 | |
| 257 | armHeartBeat(); |
| 258 | } |
nothing calls this directly
no test coverage detected