From 5563ac0c01db35e6806994f05f7db2beffb04a09 Mon Sep 17 00:00:00 2001 From: Kerry Shetline Date: Fri, 17 Jan 2020 16:49:45 -0500 Subject: [PATCH] Add randomized timing for polling to keep multiple instances of the software from polling the same servers at the same time. Fix tests broken by recent major npm package updates. --- e2e/tsconfig.e2e.json | 2 +- package-lock.json | 12 +----------- package.json | 3 +-- protractor.conf.js | 2 +- server/package-lock.json | 2 +- server/package.json | 2 +- server/src/tai-utc.ts | 9 +++++++++ spec.bundle.js | 6 ++---- src/clock.ts | 27 +++++++++++++++++---------- src/index.html | 2 +- webpack-test.config.js | 15 +++++++-------- 11 files changed, 42 insertions(+), 40 deletions(-) diff --git a/e2e/tsconfig.e2e.json b/e2e/tsconfig.e2e.json index 1d9e5ed..4334df7 100644 --- a/e2e/tsconfig.e2e.json +++ b/e2e/tsconfig.e2e.json @@ -4,7 +4,7 @@ "outDir": "../out-tsc/e2e", "baseUrl": "./", "module": "commonjs", - "target": "es5", + "target": "es6", "types": [ "jasmine", "jasminewd2", diff --git a/package-lock.json b/package-lock.json index 02db00e..780c1df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "aw-clock", - "version": "1.2.4", + "version": "1.2.5", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -6601,16 +6601,6 @@ "boolbase": "~1.0.0" } }, - "null-loader": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/null-loader/-/null-loader-3.0.0.tgz", - "integrity": "sha512-hf5sNLl8xdRho4UPBOOeoIwT3WhjYcMUQm0zj44EhD6UscMAz72o2udpoDFBgykucdEDGIcd6SXbc/G6zssbzw==", - "dev": true, - "requires": { - "loader-utils": "^1.2.3", - "schema-utils": "^1.0.0" - } - }, "num2fraction": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", diff --git a/package.json b/package.json index 6a20b85..0ecec3e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aw-clock", - "version": "1.2.4", + "version": "1.2.5", "license": "MIT", "author": "Kerry Shetline ", "scripts": { @@ -58,7 +58,6 @@ "karma-webpack": "^4.0.2", "less-loader": "^5.0.0", "node-sass": "^4.13.1", - "null-loader": "^3.0.0", "postcss-import": "^12.0.1", "postcss-loader": "^3.0.0", "postcss-url": "^8.0.0", diff --git a/protractor.conf.js b/protractor.conf.js index 94e43a5..7561400 100644 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -47,7 +47,7 @@ exports.config = { let resolved = false; let rejected = false; - webpackServerProcess = spawn('webpack-dev-server', ['--port=4200']); + webpackServerProcess = spawn('webpack-dev-server', ['--mode=development', '--port=4200']); webpackServerProcess.stdout.pipe(process.stdout); webpackServerProcess.stdout.addListener('data', chunk => { diff --git a/server/package-lock.json b/server/package-lock.json index 5b5cc78..d0bf193 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1,6 +1,6 @@ { "name": "aw-clock-server", - "version": "1.2.4", + "version": "1.2.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/server/package.json b/server/package.json index 8685cb8..c20dcc7 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "aw-clock-server", - "version": "1.2.4", + "version": "1.2.5", "license": "MIT", "author": "Kerry Shetline ", "private": true, diff --git a/server/src/tai-utc.ts b/server/src/tai-utc.ts index 6e1c341..290d91f 100644 --- a/server/src/tai-utc.ts +++ b/server/src/tai-utc.ts @@ -22,6 +22,7 @@ export const DEFAULT_LEAP_SECOND_URLS = DEFAULT_LEAP_SECOND_HTTPS_URL + ';' + DE const NTP_BASE = 2208988800; // Seconds before 1970-01-01 epoch for 1900-01-01 epoch const MILLIS_PER_DAY = 86400000; const DAYS_BETWEEN_POLLS = 7; +const MAX_RANDOM_LEAP_SECOND_POLL_DELAY = 120000; // Two minutes const TIMEOUT = 5000; const TIME_AND_DELTA = /^(\d{10,})\s+(\d{2,4})\s*#\s*1\s+[A-Za-z]{3}\s+\d{4}/; @@ -30,6 +31,7 @@ function makeError(err: any): Error { } export class TaiUtc { + private firstLeapSecondPoll = true; private lastPollDay = 0; private lastPollMonth = -1; private leapSeconds: LeapSecond[] = []; @@ -86,6 +88,13 @@ export class TaiUtc { if (this.leapSeconds.length > 1 && this.lastPollDay < day + DAYS_BETWEEN_POLLS && this.lastPollMonth === month) return; + await new Promise(resolve => { + // Randomly delay polling so that multiple TaiUtc instances don't all poll at the same time every day. + const delay = (this.firstLeapSecondPoll ? 0 : Math.floor(Math.random() * MAX_RANDOM_LEAP_SECOND_POLL_DELAY)); + this.firstLeapSecondPoll = false; + setTimeout(() => resolve(), delay); + }); + const promises: Promise[] = []; this.urls.forEach(url => { diff --git a/spec.bundle.js b/spec.bundle.js index 2d28f97..21f4ef0 100644 --- a/spec.bundle.js +++ b/spec.bundle.js @@ -1,4 +1,2 @@ -const testsContext = require.context('./', true, /\.spec\.ts$/); -testsContext.keys().forEach(key => { - if (key.indexOf('/server/') < 0) { testsContext(key); } -}); +const context = require.context('./src/', true, /\.spec\.ts$/); +context.keys().forEach(context); diff --git a/src/clock.ts b/src/clock.ts index f877ac7..9d342ae 100644 --- a/src/clock.ts +++ b/src/clock.ts @@ -28,6 +28,7 @@ import * as $ from 'jquery'; const SVG_NAMESPACE = 'http://www.w3.org/2000/svg'; const SECOND_HAND_ANIMATION_TIME = 200; +const MAX_RANDOM_LEAP_SECOND_POLL_DELAY = 120000; // Two minutes const LEAP_SECOND_RETRY_DELAY = 300000; // 5 minutes const MILLIS_PER_DAY = 86400000; @@ -63,6 +64,7 @@ export class Clock { private lastTick = -1; private inMinuteOfLeapSecond = false; private pendingLeapSecondForMonth = 0; + private firstLeapSecondPoll = true; private lastLeapSecondCheckDay = -1; private upcomingLeapSecond: CurrentDelta; @@ -349,15 +351,20 @@ export class Clock { } private getLeapSecondInfo(): void { - // noinspection JSIgnoredPromiseFromCall - $.ajax({ - url: this.appService.getWeatherServer() + '/tai-utc', - dataType: 'json', - success: (data: CurrentDelta) => this.upcomingLeapSecond = data, - error: () => setTimeout(() => { - this.upcomingLeapSecond = undefined; - this.lastLeapSecondCheckDay = -1; - }, LEAP_SECOND_RETRY_DELAY) - }); + setTimeout(() => { + this.firstLeapSecondPoll = false; + + // noinspection JSIgnoredPromiseFromCall + $.ajax({ + url: this.appService.getWeatherServer() + '/tai-utc', + dataType: 'json', + success: (data: CurrentDelta) => this.upcomingLeapSecond = data, + error: () => setTimeout(() => { + this.upcomingLeapSecond = undefined; + this.lastLeapSecondCheckDay = -1; + }, LEAP_SECOND_RETRY_DELAY) + }); + // Randomly delay polling so that multiple clock instances don't all poll at the same time every day. + }, this.firstLeapSecondPoll ? 0 : Math.floor(Math.random() * MAX_RANDOM_LEAP_SECOND_POLL_DELAY)); } } diff --git a/src/index.html b/src/index.html index 6322283..3fbdde0 100644 --- a/src/index.html +++ b/src/index.html @@ -192,7 +192,7 @@
- 1.2.4 + 1.2.5 diff --git a/webpack-test.config.js b/webpack-test.config.js index 8082238..d4f0809 100644 --- a/webpack-test.config.js +++ b/webpack-test.config.js @@ -1,15 +1,17 @@ const path = require('path'); const ROOT = path.resolve(__dirname, 'src'); +const SERVER = path.resolve(__dirname, 'server'); +const NODE_ENV = process.env.NODE_ENV || 'development'; module.exports = { + mode: NODE_ENV, context: ROOT, resolve: { extensions: ['.ts', '.js'], modules: [ ROOT, - 'node_modules', - 'server/node_modules' + 'node_modules' ] }, @@ -19,23 +21,20 @@ module.exports = { { enforce: 'pre', test: /\.js$/, + exclude: [SERVER], use: 'source-map-loader' }, // LOADERS { - test: s => s.endsWith('.ts') && !s.endsWith('/ntp.ts'), - exclude: [/node_modules/], + test: /\.ts$/, + exclude: [/node_modules/, SERVER], use: { loader: 'ts-loader', options: { transpileOnly: true } } - }, - { - test: /\/ntp\.ts$/, - use: 'null-loader' } ] },