From ce94b18d3b192fff6403daae849e10d21aac7751 Mon Sep 17 00:00:00 2001 From: sballesteros Date: Thu, 31 Oct 2019 21:29:31 -0700 Subject: [PATCH] start on azure deployments --- README.md | 20 +++++++++++ deploy-app.sh | 19 ++++++++++ deploy-service.sh | 17 +++++++++ log-app.sh | 4 +++ log-service.sh | 4 +++ package.json | 6 ++-- src/components/shell-content.js | 2 ++ src/db/feed.js | 4 ++- src/dev-server.js | 60 +++++++++++++++++++++++++++++++ src/server.js | 39 ++------------------ src/service.js | 63 +++++++++++++++++++++++++++++++++ src/utils/orcid.js | 2 +- 12 files changed, 199 insertions(+), 41 deletions(-) create mode 100755 deploy-app.sh create mode 100755 deploy-service.sh create mode 100755 log-app.sh create mode 100755 log-service.sh create mode 100644 src/dev-server.js create mode 100644 src/service.js diff --git a/README.md b/README.md index 111e262..5cc5986 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,8 @@ To add stories, add a file that ends with `.stories.js` in the `./src/components ### Web extension +#### Development + For chrome: 1. Run `npm run extension:watch` that will build and watch the extension in the `extension` directory. ! DO NOT EDIT THE FILES THERE or do not tack them on @@ -119,6 +121,14 @@ For chrome: 2. Navigate to `chrome://extensions/`, be sure to toggle the "developer mode", click on "load unpacked" and select the content of the `extension` directory. + +#### Production + +For chrome: +1. Run `npm run extension:build` +2. Navigate to `chrome://extensions/`, be sure to toggle the "developer mode", + click on "load unpacked" and select the content of the `extension` directory. + ### Tests Once cloudant is running run: @@ -126,3 +136,13 @@ Once cloudant is running run: ```sh npm test ``` + +### Deployments + +We use Azure. + +1. install Azure CLI (see https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest) +2. run `az login` to login to the CLI +3. run `./deploy-app.sh` to deploy the app and `./deploy-service.sh` to deploy the service + +To see the logs, run `./log-app.sh` or `./log-service.sh` diff --git a/deploy-app.sh b/deploy-app.sh new file mode 100755 index 0000000..85cf666 --- /dev/null +++ b/deploy-app.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +## https://rapid-prereview.azurewebsites.net/ + +## See https://docs.microsoft.com/en-us/azure/app-service/deploy-zip + +zip -r app.zip *.json *.js dist/* src/* public/* views/* scripts/* test/* + +## See https://docs.microsoft.com/en-us/azure/app-service/containers/configure-language-nodejs + +## TODO env variables: az webapp config appsettings set --name --resource-group myResourceGroup --settings MONGODB_URI="mongodb://:@.documents.azure.com:10250/mean?ssl=true" + +az webapp config appsettings set --resource-group "rapid-prereview" --name "rapid-prereview" --settings SCM_DO_BUILD_DURING_DEPLOYMENT=true + +az webapp config set --resource-group "rapid-prereview" --name "rapid-prereview" --startup-file "npm run start:prod" + +az webapp deployment source config-zip --resource-group "rapid-prereview" --name "rapid-prereview" --src app.zip + +rm app.zip diff --git a/deploy-service.sh b/deploy-service.sh new file mode 100755 index 0000000..88d8417 --- /dev/null +++ b/deploy-service.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +## https://rapid-prereview-service.azurewebsites.net/ + +## See https://docs.microsoft.com/en-us/azure/app-service/deploy-zip + +zip -r service.zip *.json *.js dist/* src/* public/* views/* scripts/* test/* + +## See https://docs.microsoft.com/en-us/azure/app-service/containers/configure-language-nodejs + +az webapp config appsettings set --resource-group "rapid-prereview" --name "rapid-prereview-service" --settings SCM_DO_BUILD_DURING_DEPLOYMENT=true + +az webapp config set --resource-group "rapid-prereview" --name "rapid-prereview-service" --startup-file "npm run start:prod" + +az webapp deployment source config-zip --resource-group "rapid-prereview" --name "rapid-prereview-service" --src service.zip + +rm service.zip diff --git a/log-app.sh b/log-app.sh new file mode 100755 index 0000000..6fb7a61 --- /dev/null +++ b/log-app.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +az webapp log config --name "rapid-prereview" --resource-group "rapid-prereview" --docker-container-logging filesystem +az webapp log tail --name "rapid-prereview" --resource-group "rapid-prereview" diff --git a/log-service.sh b/log-service.sh new file mode 100755 index 0000000..e320b6f --- /dev/null +++ b/log-service.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +az webapp log config --name "rapid-prereview-service" --resource-group "rapid-prereview" --docker-container-logging filesystem +az webapp log tail --name "rapid-prereview-service" --resource-group "rapid-prereview" diff --git a/package.json b/package.json index 1cd661d..b536b96 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,10 @@ "cloudant": "docker restart cloudant-developer", "log-cloudant": "docker logs cloudant-developer", "extension:watch": "webpack --config webpack-extension.config.js --watch --mode development", - "extension:build": "NODE_ENV=production webpack --config webpack-extension.config.js --mode production", - "start": "babel-node ./src/server.js", + "extension:build": "cross-env NODE_ENV=production webpack --config webpack-extension.config.js --mode production", + "start": "babel-node ./src/dev-server.js", + "start:prod": "node ./dist/server.js", + "start:service": "node ./dist/service.js", "seed": "babel-node ./scripts/seed.js", "ddocs": "babel-node ./scripts/ddocs.js", "init": "babel-node ./scripts/init.js", diff --git a/src/components/shell-content.js b/src/components/shell-content.js index 856998f..efa3302 100644 --- a/src/components/shell-content.js +++ b/src/components/shell-content.js @@ -206,6 +206,8 @@ function ShellContentRead({ preprint, actions, fetchActionsProgress }) { const location = useLocation(); const history = useHistory(); + // TODO make it work with the extension where we have no control on `location` + // sanitize qs useEffect(() => { if (!fetchActionsProgress.isActive) { diff --git a/src/db/feed.js b/src/db/feed.js index 0fe2011..dba309b 100644 --- a/src/db/feed.js +++ b/src/db/feed.js @@ -19,6 +19,8 @@ export default class Feed extends EventEmitter { this.seq = since; + this.emit('start', this.seq); + this.feed = this.db.docs.follow({ since, include_docs: true }); this.feed.on('change', async change => { const { doc } = change; @@ -53,7 +55,7 @@ export default class Feed extends EventEmitter { } async resume() { - const seq = this.db.getLatestTriggeringSeq(); + const seq = await this.db.getLatestTriggeringSeq(); return this.start({ since: seq }); } diff --git a/src/dev-server.js b/src/dev-server.js new file mode 100644 index 0000000..e8b5663 --- /dev/null +++ b/src/dev-server.js @@ -0,0 +1,60 @@ +import http from 'http'; +import express from 'express'; +import webpack from 'webpack'; +import webpackDevMiddleware from 'webpack-dev-middleware'; +import webpackHotMiddleware from 'webpack-hot-middleware'; +import webpackConfig from '../webpack.config'; +import DB from '../src/db/db'; +import Feed from '../src/db/feed'; +import { rapid, assets } from './index'; +import { + setIntervalAsync, + clearIntervalAsync +} from './utils/set-interval-async'; + +const compiler = webpack(webpackConfig); + +const config = { + disableSsr: true +}; + +const db = new DB(config); +const feed = new Feed(db); +feed.start(); // TODO use feed.resume() +feed.on('error', err => { + console.error(err); +}); + +const intervalId = setIntervalAsync( + () => { + return db.updateScores(); + }, + 5 * 60 * 1000, + err => console.error(err) +); + +const app = express(); +app.use( + webpackDevMiddleware(compiler, { + publicPath: webpackConfig.output.publicPath + }) +); +app.use(webpackHotMiddleware(compiler)); + +app.use(assets(config)); +app.use(rapid(config)); + +const server = http.createServer(app); + +const port = 3000; +server.listen(port, () => { + console.log(`server listenning on port ${port}`); +}); + +process.once('SIGINT', function() { + server.close(() => { + clearIntervalAsync(intervalId); + feed.stop(); + process.exit(); + }); +}); diff --git a/src/server.js b/src/server.js index 8487e67..f08ddc0 100644 --- a/src/server.js +++ b/src/server.js @@ -1,60 +1,25 @@ import http from 'http'; import express from 'express'; -import webpack from 'webpack'; -import webpackDevMiddleware from 'webpack-dev-middleware'; -import webpackHotMiddleware from 'webpack-hot-middleware'; -import webpackConfig from '../webpack.config'; -import DB from '../src/db/db'; -import Feed from '../src/db/feed'; import { rapid, assets } from './index'; -import { - setIntervalAsync, - clearIntervalAsync -} from './utils/set-interval-async'; - -const compiler = webpack(webpackConfig); const config = { + isBeta: true, disableSsr: true }; -const db = new DB(config); -const feed = new Feed(db); -feed.start(); // TODO use feed.resume() -feed.on('error', err => { - console.error(err); -}); - -const intervalId = setIntervalAsync( - () => { - return db.updateScores(); - }, - 5 * 60 * 1000, - err => console.error(err) -); - const app = express(); -app.use( - webpackDevMiddleware(compiler, { - publicPath: webpackConfig.output.publicPath - }) -); -app.use(webpackHotMiddleware(compiler)); - app.use(assets(config)); app.use(rapid(config)); const server = http.createServer(app); -const port = 3000; +const port = process.env.PORT || 3000; server.listen(port, () => { console.log(`server listenning on port ${port}`); }); process.once('SIGINT', function() { server.close(() => { - clearIntervalAsync(intervalId); - feed.stop(); // TODO store latest seq to disk ? process.exit(); }); }); diff --git a/src/service.js b/src/service.js new file mode 100644 index 0000000..9a7f6af --- /dev/null +++ b/src/service.js @@ -0,0 +1,63 @@ +import http from 'http'; +import express from 'express'; +import DB from '../src/db/db'; +import Feed from '../src/db/feed'; +import { + setIntervalAsync, + clearIntervalAsync +} from './utils/set-interval-async'; + +let lastSeq = null; +let lastErr = null; +let lastDateScoreUpdated = null; + +const config = { + isBeta: true, + disableSsr: true +}; + +const db = new DB(config); +const feed = new Feed(db); +feed.resume(); +feed.on('error', err => { + console.error(err); +}); +feed.on('start', seq => { + lastSeq = seq; +}); +feed.on('sync', seq => { + lastSeq = seq; +}); +feed.on('error', err => { + lastErr = err; +}); + +const intervalId = setIntervalAsync( + () => { + lastDateScoreUpdated = new Date().toISOString(); + return db.updateScores(); + }, + 5 * 60 * 1000, + err => console.error(err) +); + +const app = express(); + +app.get('/', (req, res, next) => { + res.json({ lastSeq, lastErr, lastDateScoreUpdated }); +}); + +const server = http.createServer(app); + +const port = process.env.PORT || 3000; +server.listen(port, () => { + console.log(`server listenning on port ${port}`); +}); + +process.once('SIGINT', function() { + server.close(() => { + clearIntervalAsync(intervalId); + feed.stop(); + process.exit(); + }); +}); diff --git a/src/utils/orcid.js b/src/utils/orcid.js index 607c65c..d19b757 100644 --- a/src/utils/orcid.js +++ b/src/utils/orcid.js @@ -95,7 +95,7 @@ export function createPassport(config) { process.env.APP_ROOT_URL || 'http://127.0.0.1:3000'}/auth/orcid/callback`; - if (process.env.NODE_ENV === 'production') { + if (process.env.NODE_ENV === 'production' && !config.isBeta) { strategy = new OrcidStrategy( { sandbox: false, // remove this to use the production API