Skip to content

Commit 0ae021b

Browse files
authored
Merge pull request #5 from oslabs-beta/staging
First merge
2 parents 9908349 + 4b23a2c commit 0ae021b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+8888
-2218
lines changed

.DS_Store

0 Bytes
Binary file not shown.

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
node_modules
22
.eslintrc.js
33
package-lock.json
4-
settings.json
5-
.DS_Store
4+
.DS_Store
5+
user/settings.json

Chronos Slide Deck Notes.rtf

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
{\rtf1\ansi\ansicpg1252\cocoartf1561\cocoasubrtf610
2+
{\fonttbl\f0\fnil\fcharset0 Georgia;}
3+
{\colortbl;\red255\green255\blue255;}
4+
{\*\expandedcolortbl;;}
5+
\margl1011\margr1011\margb1445\margt1011\vieww14300\viewh16300\viewkind1\viewscale113
6+
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\fi722\sl288\slmult1\pardirnatural\partightenfactor0
7+
8+
\f0\b\fs24 \cf0 about Chronos
9+
\b0 \
10+
- a microservice network monitoring tool\
11+
- designed to meet the needs of companies and developers who are breaking down their monolithic system architectures into decoupled distributed services, an system design known as microservices. Microservices applications are deployed as a family of independent services, each with a specific function to perform. When you break down a traditional monolithic system into manageable sections, it\'92s not always an easy task. You still need the individual pieces to communicate with one another and work in tandem and it requires more real-time attention and proactive monitoring. And at every one of these points of communication is a potential point of failure. Tracking an application requires correlating data from all these different services. So a common problem of breaking down a large-scale application can produce a series of problems, such as complex communication conflicts with the disparate teams that are now working on their own piece of the pie. \
12+
- Many companies utilize microservices, even though they are huge corporations such as Amazon, which turned to a microservice architecture back in 2001 and has their cloud monitoring tool called Amazon X-Ray, Twitter, and Netflix, which has their own in-house microservice tool.\
13+
\
14+
15+
\b how it works\
16+
17+
\b0 - install an NPM packages into each of your services, provide a database connection string, and you\'92re able to look at how your application is faring at any given moment.\
18+
- it uses a process called context propagation, where a wrapper is placed around incoming HTTP requests and when any subsequent requests are triggered, a correlation ID is given to that specific request as a request header. Thereby, that same correlation ID will connect multiple disparate endpoints of an application, and so if there\'92s any problems, a team of devs working on one area of an application can trace the origin of any issue, even if it originated from another team\'92s scope of purview. These endpoints converse with each other and return the operational status of a service and an indication of its ability to connect to downstream dependent services as an HTTP status code with JSON data, creating an aggregated web of responses that allows for better communication and accessibility.\
19+
- for example, Amazon does one-click ordering and they are the best at this. Let\'92s say, for instance, it usually takes 3ms to complete an order. If, for some reason it now takes 5ms, Amazon\'92s health monitoring tool would alert them to this issue, and because of the way context propagation works, they would be able to drill down their endpoints across various services and departments and directly assess the situation wherever it may occur in the application. \
20+
\
21+
22+
\b what you get\
23+
24+
\b0 - by accessing systems information API, you\'92re able to get data pertinent to the health of the server on which Chronos operates on. this is useful because if a service is running a bit behind or something unusual is going on, we\'92ll know exactly where it\'92s happening and whether or not this is a consistent problem or something unique.\
25+
- this data connects to your very own database, you can use either mongo or postgresql, which will keep your private data private.\
26+
- you\'92re able to see a dashboard display that provides data over time on distinctive metrics such as speed and latency tracking (intervals can be set from either every sec to every week), process monitoring, as well as memory usage. It should look like a graph display that records performance and health over time. It\'92ll provide much-needed context for an engineer to assess the situation handily. A key detail is that system performance is not binary; systems are not on or off. They can operate in degraded state that impacts performance, often leading to failure. A graph system provides context to a degraded state before total failure can occur.\
27+
- we plan on building a communication helper tool to send you an alert through Slack or email, alerts will be the first line of defense in assessing application health\
28+
- it helps you to develop, debug, and deliver code faster, which, in turn, makes for better productivity and more importantly, happiness in devs
29+
\b \
30+
\
31+
\
32+
technology stack
33+
\b0 \
34+
\
35+
-
36+
\i Docker\
37+
38+
\i0 - Provides containerization of microservice dummy app. We are also looking into orchestration tools such as Kubernetes to kill an instance of a service or raise an alert to Chronos in case of a failing health check. Containers and microservices go hand in hand by by sharing system resources, thereby making them leaner and reducing system overhead, and result in faster and easier scaling.\
39+
-
40+
\i React Context API
41+
\i0 \
42+
- Because our components are multiple and not directly connected, React\'92s Context API becomes very useful. It will help us cache queried information for use by functional React components associated with the visual display of information. It consists of three building blocks: Context Object refers to data shared across component boundaries, Context Provider allows us to use the Context API as a global state management tool by wrapping all child components that will eventually need access to the Context, and Context Consumer helps to update parent/child components based on some centralized state\
43+
- Context Object: data shared across component boundaries\
44+
- Context Provider: with Context created, we can now provide an object as a value to all components that interact with it (reading data, triggering methods). It is provided in a component that wraps all of its child components that will eventually need access to the Context. If you need data to be available throughout your entire app, just provide Context in the root component, like the App component. Allows us to use Context API as a global state management tool.\
45+
- Context Consumer: it is a wrapper component we can use to inject Context provided in some parent component into a child component. When data from our parent changes, the context object in our child component also changes and updates. This helps to update different components based on some centralized state\
46+
-
47+
\i React Hooks
48+
\i0 \
49+
- we can use Context and React Hooks in functional components\
50+
-
51+
\i React Router
52+
\i0 \
53+
\
54+
-
55+
\i Redux
56+
\i0 \
57+
- helps to manage the data you need to render user interface correctly, or state, of a React app\
58+
- In React, we sometimes run into the issue, especially with complex apps, of passing props (which is data from a parent component) that we don\'92t necessarily have to handle. Any changes to an app\'92s state or component structure would require significant refactoring. We won\'92t go into too much detail\
59+
\
60+
-
61+
\i Async Hooks\
62+
63+
\i0 - Node.js API will be used to persist the correlation ID across asynchronous callback functions so that a unique request can be traced back from wherever it was alerted.\
64+
-
65+
\i Electron
66+
\i0 \
67+
- an application used to render Chronos with full access to the Node environment\
68+
- Slack is built on Electron\
69+
\
70+
-
71+
\i Node.js, Express, Charts.js, Spectron, Jest, \
72+
- infrastructure monitoring: \
73+
- Prometheus\
74+
75+
\i0 - an open-sourced monitoring solution originally developed by SoundCloud. It is used to store and query data that describes actions over time. It will assist us in visualizing the time-series data and to provide dashboards. Often used with Grafana, something we\'92ll look into.\
76+
77+
\i \
78+
-Nagios\
79+
80+
\i0 - open-sourced, as well. Assists in continuous server monitoring, an automated approach essential for visibility into infrastructure and applications.\
81+
82+
\i \
83+
- application monitoring: Jaeger\
84+
\
85+
86+
\i0\b technical challenges\
87+
88+
\b0 - Diving into an unfamiliar technology stack\
89+
- Understanding how context propagation works under the hood\
90+
- Utilizing a proxy server to dynamically route client requests to the appropriate service\
91+
\
92+
\
93+
94+
\b stretch
95+
\b0 \
96+
- Travis CI for testing and deployment, linking containers with yaml files, orchestration system like Kubernetes, \
97+
\
98+
99+
\b what we plan to do\
100+
101+
\b0 - create an intuitive and modern UI-centric Electron app with a dashboard that is well-designed and accurately reflects the health of the microservice.\
102+
- use Nginx (\'93engine X\'94) to create a reverse proxy server for back-end routing and caching. This proxy server, in a way, acts as a middleware server to help us route client requests to server. Nginx is one of the top open-sourced web servers.\
103+
- implement metrics to flesh out our health report: average execution time of each of the top ten most frequently executed database queries, average response time for each service endpoint, success/failure ratio for each service. An aggregated set of data can alert us to any system-wide degradation of performance that can potentially lead to failure of the entire system.\
104+
\
105+
106+
\b conclusion\
107+
108+
\b0 - it is just as important to collect relevant data as it is to analyze data that is collected. This data is critical to support a distributed system that is resilient, reliable, and available. Chronos is here to help with that.\
109+
\
110+
}

Main.js

Lines changed: 60 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// node requirements
2-
const {
3-
dialog, app, BrowserWindow, ipcMain,
4-
} = require('electron');
2+
const { dialog, app, BrowserWindow, ipcMain } = require('electron');
53
const fs = require('fs');
64
const path = require('path');
75
const connectSQL = require('./model/sql-connect');
@@ -20,9 +18,9 @@ function createWindow() {
2018
// assign win to an instance of a new browser window.
2119
win = new BrowserWindow({
2220
// giving our window its width
23-
width: 900,
21+
width: 1920,
2422
// giving our window its hieght
25-
height: 800,
23+
height: 1080,
2624
// specify the path of the icon -- Which icon is this?.. note too tsure --> Ousman
2725
icon: path.join(__dirname, 'app/assets/icons/icon.png'),
2826
// enable node inegreation --> node intgeration, default is usally false --> Ousman
@@ -44,11 +42,16 @@ function createWindow() {
4442
// read json from settings.json
4543
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
4644
encoding: 'UTF-8',
47-
}),
45+
})
4846
);
4947
// reassign state.splash
5048
state.splash = true;
51-
fs.writeFileSync(path.resolve(__dirname, './user/settings.json'), JSON.stringify(state), { encoding: 'UTF-8' }); win = null;
49+
fs.writeFileSync(
50+
path.resolve(__dirname, './user/settings.json'),
51+
JSON.stringify(state),
52+
{ encoding: 'UTF-8' }
53+
);
54+
win = null;
5255
});
5356
}
5457

@@ -62,11 +65,15 @@ app.on('window-all-closed', () => {
6265
// read json from settings.json
6366
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
6467
encoding: 'UTF-8',
65-
}),
68+
})
6669
);
6770
// reassign state.splash
6871
state.splash = true;
69-
fs.writeFileSync(path.resolve(__dirname, './user/settings.json'), JSON.stringify(state), { encoding: 'UTF-8' });
72+
fs.writeFileSync(
73+
path.resolve(__dirname, './user/settings.json'),
74+
JSON.stringify(state),
75+
{ encoding: 'UTF-8' }
76+
);
7077
// process platform is a property that return a string identifying the OS platform on which NodeJs process is running --> Ousman
7178
if (process.platform !== 'darwin') {
7279
// quits application
@@ -85,29 +92,33 @@ app.on('activate', () => {
8592
// Fired by the useEffect hook inside of the Splash.jsx component, this message route will toggle
8693
// splash property inside of settings.json to false once the Splash page renders itself just once
8794
ipcMain.on('toggleSplash', (message) => {
88-
//console.log('toggleSplash message received');
95+
// console.log('toggleSplash message received');
8996
const state = JSON.parse(
9097
// read json from settings.json
9198
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
9299
encoding: 'UTF-8',
93-
}),
100+
})
94101
);
95102
// reassign state.splash to false
96103
state.splash = false;
97104

98105
// overwrite settings.json with false splash property
99-
fs.writeFileSync(path.resolve(__dirname, './user/settings.json'), JSON.stringify(state), { encoding: 'UTF-8' });
106+
fs.writeFileSync(
107+
path.resolve(__dirname, './user/settings.json'),
108+
JSON.stringify(state),
109+
{ encoding: 'UTF-8' }
110+
);
100111

101112
message.returnValue = state.splash;
102113
});
103114

104115
ipcMain.on('checkSplash', (message) => {
105-
//sconsole.log('checkSplash message received');
116+
// sconsole.log('checkSplash message received');
106117
const state = JSON.parse(
107118
// read json from settings.json
108119
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
109120
encoding: 'UTF-8',
110-
}),
121+
})
111122
);
112123

113124
message.returnValue = state.splash;
@@ -116,13 +127,13 @@ ipcMain.on('checkSplash', (message) => {
116127
// Load settings JSON and returns current setup status back to the render process.
117128
// ipc 'setup' route --> Ousman
118129
ipcMain.on('setup', (message) => {
119-
//console.log('setup message received');
130+
// console.log('setup message received');
120131
// assigns state to the returned the object returned from settings.json --> Ousman
121132
const state = JSON.parse(
122133
// read json from settings.json
123134
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
124135
encoding: 'UTF-8',
125-
}),
136+
})
126137
);
127138
// destructure setupRequired from state constant ---> Ousman
128139
const { setupRequired } = state;
@@ -137,21 +148,24 @@ ipcMain.on('submit', (message, newService) => {
137148
const state = JSON.parse(
138149
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
139150
encoding: 'UTF-8',
140-
}),
151+
})
141152
);
142153

143-
// Checks if setup is required by checking if the value for the state key 'setupRequired' is true
154+
// Checks if setup is required by checking if the value for the state key 'setupRequired' is true
144155
if (state.setupRequired) {
145156
// If setup is required, the value for key 'setupRequired' is reassign to false and the value for key 'services' is reassign to an array with newService as its only element
146157
state.setupRequired = false;
147158
state.services = [JSON.parse(newService)];
148159
} else {
149160
// Else the newService is pushed into the services array
150161
state.services.push(JSON.parse(newService));
151-
}
162+
}
152163

153164
// Rewrites user/settings.json to show state
154-
fs.writeFileSync(path.resolve(__dirname, './user/settings.json'), JSON.stringify(state));
165+
fs.writeFileSync(
166+
path.resolve(__dirname, './user/settings.json'),
167+
JSON.stringify(state)
168+
);
155169
});
156170

157171
// Load settings JSON and returns updated state back to the render process.
@@ -161,7 +175,7 @@ ipcMain.on('dashboard', (message) => {
161175
const state = JSON.parse(
162176
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
163177
encoding: 'UTF-8',
164-
}),
178+
})
165179
);
166180
// destructure services from state... what is services? --> Ousman
167181
const { services } = state;
@@ -180,31 +194,36 @@ ipcMain.on('deleteService', (message, index) => {
180194
let state = JSON.parse(
181195
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
182196
encoding: 'UTF-8',
183-
}),
197+
})
184198
);
185199

186200
// Send a response back with the updated services
187201
const { splash } = state;
188-
// Checks if there is more than one services in the services array
202+
// Checks if there is more than one services in the services array
189203
if (state.services.length > 1) {
190-
// If true, removes the service at position 'index'
204+
// If true, removes the service at position 'index'
191205
state.services.splice(index, 1);
192206
} else {
193-
// Else reassign state to what the user/setting.json file was originally before any database was save
207+
// Else reassign state to what the user/setting.json file was originally before any database was save
194208
state = { setupRequired: true, services: ['hard', 'coded', 'in'], splash };
195209
}
196210

197211
// Rewrites json from settings.json
198-
fs.writeFileSync(path.resolve(__dirname, './user/settings.json'), JSON.stringify(state), { encoding: 'UTF-8' });
212+
fs.writeFileSync(
213+
path.resolve(__dirname, './user/settings.json'),
214+
JSON.stringify(state),
215+
{ encoding: 'UTF-8' }
216+
);
199217
message.sender.send('deleteResponse', state.services);
200218
});
201219

202-
203220
// Queries the database for communications information and returns it back to the render process.
204221
ipcMain.on('overviewRequest', (message, index) => {
205222
console.log('hello from overview request');
206223
const { services } = JSON.parse(
207-
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), { encoding: 'UTF-8' }),
224+
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
225+
encoding: 'UTF-8',
226+
})
208227
);
209228

210229
const databaseType = services[index][1];
@@ -233,14 +252,16 @@ ipcMain.on('overviewRequest', (message, index) => {
233252
const errorAlert = {
234253
type: 'error',
235254
title: 'Error in Main process',
236-
message: 'Database information could not be retreived. Check that table exists.',
255+
message:
256+
'Database information could not be retreived. Check that table exists.',
237257
};
238258

239259
// after requiring dialog in the topmost section of main. We invoke the method showMessagebox passing the error object we created --> Ousman
240260
dialog.showMessageBox(errorAlert);
241261

242-
243-
message.sender.send(JSON.stringify('Database info could not be retreived.'));
262+
message.sender.send(
263+
JSON.stringify('Database info could not be retreived.')
264+
);
244265
} else {
245266
console.log('Connected to SQL Database');
246267
const queryResults = JSON.stringify(result.rows);
@@ -256,7 +277,9 @@ ipcMain.on('overviewRequest', (message, index) => {
256277
ipcMain.on('detailsRequest', (message, index) => {
257278
console.log('detailsRequest message received');
258279
const databaseType = JSON.parse(
259-
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), { encoding: 'UTF-8' }),
280+
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
281+
encoding: 'UTF-8',
282+
})
260283
).services[index][1];
261284

262285
if (databaseType === 'MongoDB') {
@@ -267,14 +290,18 @@ ipcMain.on('detailsRequest', (message, index) => {
267290
const queryResults = JSON.stringify(data);
268291
// Asynchronous event emitter used to transmit query results back to the render process.
269292
message.sender.send('detailsResponse', queryResults);
293+
console.log('Message Sent');
270294
});
271295
}
272296

273297
if (databaseType === 'SQL') {
274298
const getHealth = 'SELECT * FROM healthInfo';
275299
pool.query(getHealth, (err, result) => {
276300
if (err) {
277-
message.sender.send('detailsResponse', JSON.stringify('Database info could not be retreived.'));
301+
message.sender.send(
302+
'detailsResponse',
303+
JSON.stringify('Database info could not be retreived.')
304+
);
278305
}
279306
const queryResults = JSON.stringify(result.rows);
280307
// Asynchronous event emitter used to transmit query results back to the render process.
@@ -283,4 +310,3 @@ ipcMain.on('detailsRequest', (message, index) => {
283310
});
284311
}
285312
});
286-

app/.DS_Store

0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)