Skip to content

Commit b61f740

Browse files
committed
Singlethreaded implementation
1 parent ab691ee commit b61f740

File tree

9 files changed

+207
-0
lines changed

9 files changed

+207
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use strict';
2+
3+
const ActorSystem = require('../system');
4+
const nodemailer = require('nodemailer');
5+
const auth = require('../config');
6+
7+
const FROM = 'nodeua.com@gmail.com';
8+
9+
ActorSystem.register(class Mailer {
10+
constructor() {
11+
console.log('Start actor: Mailer');
12+
this.transport = nodemailer.createTransport({
13+
service: 'gmail', auth
14+
});
15+
}
16+
17+
message({ to, subject, message }) {
18+
const mail = { from: FROM, to, subject, text: message };
19+
this.transport.sendMail(mail, (error, data) => {
20+
if (error) console.log(error);
21+
else console.log(`Email sent: ${data.response}`);
22+
});
23+
}
24+
25+
async exit() {
26+
this.transport.close();
27+
console.log('Stop actor: Mailer');
28+
}
29+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use strict';
2+
3+
const ActorSystem = require('../system');
4+
const http = require('http');
5+
6+
const URL = 'http://localhost:8000/';
7+
const INTERVAL = 2000;
8+
9+
ActorSystem.register(class Monitoring {
10+
constructor() {
11+
console.log('Start actor: Monitoring');
12+
this.prevSuccess = true;
13+
this.timer = setInterval(() => {
14+
this.attempt(URL);
15+
}, INTERVAL);
16+
}
17+
18+
attempt(url) {
19+
http.get(url, res => {
20+
const success = res.statusCode === 200;
21+
this.notify({ url, success, status: res.statusCode });
22+
}).on('error', error => {
23+
this.notify({ url, success: false, status: error.message });
24+
});
25+
}
26+
27+
notify({ url, success, status }) {
28+
if (this.prevSuccess !== success) {
29+
this.prevSuccess = success;
30+
ActorSystem.send('Renderer', { url, success, status });
31+
}
32+
}
33+
34+
message() {}
35+
36+
async exit() {
37+
clearInterval(this.timer);
38+
console.log('Stop actor: Monitoring');
39+
}
40+
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
3+
const ActorSystem = require('../system');
4+
5+
ActorSystem.register(class Renderer {
6+
constructor() {
7+
console.log('Start actor: Renderer');
8+
}
9+
10+
message({ url, success, status }) {
11+
const to = 'nodeua.com@gmail.com';
12+
const msg = success ? 'is available again' : 'is not available';
13+
const date = new Date().toUTCString();
14+
const reason = (success ? 'Status code: ' : 'Error code: ') + status;
15+
const message = `Resource ${url} ${msg} (${date})\n${reason}`;
16+
const subject = 'Server Monitoring';
17+
ActorSystem.send('Mailer', { to, subject, message });
18+
}
19+
20+
async exit() {
21+
console.log('Stop actor: Renderer');
22+
}
23+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
const ActorSystem = require('../system');
4+
5+
ActorSystem.register(class Root {
6+
constructor() {
7+
console.log('Start actor: Root');
8+
ActorSystem.start('Monitoring');
9+
ActorSystem.start('Renderer');
10+
ActorSystem.start('Mailer');
11+
}
12+
13+
message() {}
14+
15+
async exit() {
16+
setTimeout(() => {
17+
console.log('Abnormal termination');
18+
process.exit(1);
19+
}, 10000);
20+
await ActorSystem.stop('Monitoring');
21+
await ActorSystem.stop('Renderer');
22+
await ActorSystem.stop('Mailer');
23+
console.log('Stop actor: Root');
24+
console.log('Graceful shutdown');
25+
process.exit(0);
26+
}
27+
});

JavaScript/1-singletrhead/config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
'use strict';
2+
3+
module.exports = {
4+
user: 'account-name@gmail.com',
5+
pass: 'your-password',
6+
};

JavaScript/1-singletrhead/main.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
'use strict';
2+
3+
const ActorSystem = require('./system.js');
4+
5+
ActorSystem.start('Root');
6+
7+
process.on('SIGINT', () => {
8+
console.log();
9+
ActorSystem.stop('Root');
10+
});

JavaScript/1-singletrhead/package-lock.json

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "server-monitoring",
3+
"version": "1.0.0",
4+
"description": "Actor Model example application",
5+
"main": "main.js",
6+
"repository": {
7+
"type": "git",
8+
"url": "git+https://github.com/HowProgrammingWorks/ActorModel.git"
9+
},
10+
"author": "Timur Shemsedinov <timur.shemsedinov@gmail.com>",
11+
"license": "MIT",
12+
"bugs": {
13+
"url": "https://github.com/HowProgrammingWorks/ActorModel/issues"
14+
},
15+
"homepage": "https://github.com/HowProgrammingWorks/ActorModel#readme",
16+
"dependencies": {
17+
"nodemailer": "^6.1.1"
18+
}
19+
}

JavaScript/1-singletrhead/system.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use strict';
2+
3+
const actors = new Map();
4+
5+
class ActorSystem {
6+
static register(actor) {
7+
const instances = [];
8+
const next = 0;
9+
actors.set(actor.name, { actor, instances, next });
10+
}
11+
12+
static start(name) {
13+
require('./actors/' + name.toLowerCase() + '.js');
14+
const record = actors.get(name);
15+
if (record) {
16+
const ActorClass = record.actor;
17+
const { instances } = record;
18+
const instance = new ActorClass();
19+
instances.push(instance);
20+
}
21+
}
22+
23+
static async stop(name) {
24+
const record = actors.get(name);
25+
if (record) {
26+
const { instances } = record;
27+
await Promise.all(instances.map(instance => instance.exit()));
28+
}
29+
}
30+
31+
static send(name, data) {
32+
const record = actors.get(name);
33+
if (record) {
34+
const { instances } = record;
35+
instances[0].message(data);
36+
}
37+
}
38+
}
39+
40+
module.exports = ActorSystem;

0 commit comments

Comments
 (0)