Skip to content

Commit

Permalink
feat: added Application interface
Browse files Browse the repository at this point in the history
  • Loading branch information
mvegter committed Apr 28, 2020
1 parent 4062886 commit 3c3b488
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 43 deletions.
61 changes: 56 additions & 5 deletions lib/application/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,61 @@
* or submit itself to any jurisdiction.
*/

const { Application } = require('./interfaces');
const database = require('../database');
const Server = require('../server');
const persistence = require('../database');

module.exports = {
server: new Server(),
persistence,
};
const _1_S_IN_MS = 1000;
const SHUTDOWN_DELAY_MS = 5 * _1_S_IN_MS;

/**
* Bookkeeping Application
*/
class BookkeepingApplication extends Application {
/**
* Creates a new `Bookkeeping Application` instance.
*/
constructor() {
super();

this.server = new Server();
this.database = database;
}

/**
* Causes the application to be scheduled for execution.
*
* @returns {Promise} Promise object represents the outcome.
*/
async run() {
try {
await this.server.listen();
} catch (error) {
// TODO: add logging
return this.stop();
}
}

/**
* Begins the process of terminating the application. Calling this method terminates the process.
*
* @param {Boolean} [immediate=false] Indicates if the underlying services should be closed immediately; if *false*
* it will close the underlying services gracefully.
* @returns {Promise} Promise object represents the outcome.
*/
async stop(immediate) {
this.server.acceptIncomingConnections(false);

if (immediate) {
return this.server.close();
}

setTimeout(async () => {
this.server.close()
.then(() => process.exit(0))
.catch(() => process.exit(1));
}, SHUTDOWN_DELAY_MS);
}
}

module.exports = new BookkeepingApplication();
39 changes: 39 additions & 0 deletions lib/application/interfaces/Application.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @license
* Copyright CERN and copyright holders of ALICE O2. This software is
* distributed under the terms of the GNU General Public License v3 (GPL
* Version 3), copied verbatim in the file "COPYING".
*
* See http://alice-o2.web.cern.ch/license for full licensing information.
*
* In applying this license CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*/

/**
* Application
*/
class Application {
/**
* Causes the application to be scheduled for execution.
*
* @returns {Promise} Promise object represents the outcome.
*/
async run() {
return Promise.reject('The method or operation is not implemented.');
}

/**
* Begins the process of terminating the application. Calling this method terminates the process.
*
* @param {Boolean} [immediate=false] Indicates if the underlying services should be closed immediately; if *false*
* it will close the underlying services gracefully.
* @returns {Promise} Promise object represents the outcome.
*/
async stop(immediate) {
return Promise.reject('The method or operation is not implemented.');
}
}

module.exports = Application;
2 changes: 2 additions & 0 deletions lib/application/interfaces/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
* or submit itself to any jurisdiction.
*/

const Application = require('./Application');
const Repository = require('./Repository');
const Server = require('./Server');
const UseCase = require('./UseCase');

module.exports = {
Application,
Repository,
Server,
UseCase,
Expand Down
29 changes: 3 additions & 26 deletions lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,13 @@
* or submit itself to any jurisdiction.
*/

const { server } = require('./application');
const application = require('./application');

const SHUTDOWN_DELAY_MS = 5 * 1000;

server.listen();

/**
* Stops the application.
*
* @returns {undefined}
*/
const doGracefulShutdown = () => {
server.close()
.then(() => process.exit(0))
.catch(() => process.exit(1));
};

/**
* Starts the graceful shutdown process.
*
* @returns {undefined}
*/
const startGracefulShutdown = () => {
server.acceptIncomingConnections(false);
setTimeout(doGracefulShutdown, SHUTDOWN_DELAY_MS);
};
application.run();

/*
* 'SIGTERM' and 'SIGINT' have default handlers on non-Windows platforms that reset the terminal mode before exiting
* with code 128 + signal number. If one of these signals has a listener installed, its default behavior will be removed
* (Node.js will no longer exit).
*/
['SIGTERM', 'SIGINT'].forEach((event) => process.on(event, startGracefulShutdown));
['SIGTERM', 'SIGINT'].forEach((event) => process.on(event, application.stop.bind(application)));
4 changes: 2 additions & 2 deletions lib/server/controllers/logs.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/

const { log: { GetAllLogsUseCase } } = require('../../application/usecases');
const { repositories: { LogRepository } } = require('../../database');

/**
* Create a new log
Expand Down Expand Up @@ -82,7 +83,6 @@ const getAttachment = (request, response, next) => {
/**
* Get all logs.
*
* @param {Object} application The *application* object represents the Application.
* @param {Object} request The *request* object represents the HTTP request and has properties for the request query
* string, parameters, body, HTTP headers, and so on.
* @param {Object} response The *response* object represents the HTTP response that an Express app sends when it gets an
Expand All @@ -91,7 +91,7 @@ const getAttachment = (request, response, next) => {
* next middleware function.
* @returns {undefined}
*/
const index = async ({ persistence: { repositories: { LogRepository } } }, request, response, next) => {
const index = async (request, response, next) => {
let logs;
try {
logs = await new GetAllLogsUseCase()
Expand Down
1 change: 1 addition & 0 deletions lib/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class WebServer extends Server {
* @returns {Promise} Promise object represents ...
*/
async listen() {
this.acceptIncomingConnectionsFlag = true;
return this.http.listen();
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/application/usecases/log/GetAllLogsUseCase.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* or submit itself to any jurisdiction.
*/

const { persistence: { repositories: { LogRepository } } } = require('../../../../lib/application');
const { repositories: { LogRepository } } = require('../../../../lib/database');
const { log: { GetAllLogsUseCase } } = require('../../../../lib/application/usecases');
const chai = require('chai');

Expand Down
8 changes: 5 additions & 3 deletions test/e2e/home.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ chai.use(chaiResponseValidator(path.resolve(__dirname, '..', '..', 'spec', 'open

module.exports = () => {
describe('GET /api/', () => {
const { server } = require('../../lib/application');
const application = require('../../lib/application');

const { server } = application;

before(async () => {
await server.listen();
await application.run();
});

after(async () => {
await server.close();
await application.stop(true);
});

it('should satisfy OpenAPI spec', (done) => {
Expand Down
8 changes: 5 additions & 3 deletions test/e2e/shutdown.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@ const { expect } = chai;
chai.use(chaiResponseValidator(path.resolve(__dirname, '..', '..', 'spec', 'openapi.yaml')));

module.exports = () => {
const { server } = require('../../lib/application');
const application = require('../../lib/application');

const { server } = application;

before(async () => {
await server.listen();
await application.run();
});

after(async () => {
await server.close();
await application.stop(true);
});

it('should return the server information when the server is not in shutdown', (done) => {
Expand Down
8 changes: 5 additions & 3 deletions test/public/overview.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
const assert = require('assert');
const puppeteer = require('puppeteer');
const pti = require('puppeteer-to-istanbul');
const { server } = require('../../lib/application');
const application = require('../../lib/application');

module.exports = function () {
// Configure this suite to have a default timeout of 5s
Expand All @@ -24,8 +24,10 @@ module.exports = function () {
let browser;
let url;

const { server } = application;

before(async () => {
await server.listen();
await application.run();
browser = await puppeteer.launch({ args: ['--no-sandbox'] });
page = await browser.newPage();
await Promise.all([
Expand All @@ -49,7 +51,7 @@ module.exports = function () {

pti.write([...jsCoverage, ...cssCoverage]);
await browser.close();
await server.close();
await application.stop(true);
});

it('loads the page successfully', async () => {
Expand Down

0 comments on commit 3c3b488

Please sign in to comment.