forked from cdnexperts/cdnselector
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcdns-frontend.js
executable file
·165 lines (146 loc) · 5.19 KB
/
cdns-frontend.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*jslint node: true */
"use strict";
// Dependencies
var cluster = require('cluster'),
net = require('net'),
async = require('async'),
os = require('os'),
localConfig = require('./libs/localConfig'),
database = require('./libs/database')(localConfig.dbUrl, localConfig.dbName),
loggers = require('./libs/logger'),
tokenValidator = require('./libs/tokenValidator'),
HttpServer = require('./libs/servers/HttpServer'),
CDNSelector = require('./libs/CDNSelector'),
LoadBalancer = require('./libs/LoadBalancer');
function checkPort(port, callback) {
var server = net.createServer(),
portAvailable = false;
server.listen(port);
server.on('listening', function () {
portAvailable = true;
server.close();
});
server.on('error', function (err) {
callback(err, false);
});
server.on('close', function () {
callback(null, true);
});
}
function errorExit(err) {
loggers.errorlog.error(err, err.stack);
loggers.errorlog.error('Cannot start application. Please resolve all errors and try again');
process.exit(1);
}
function startWorker(startupCompleteCallback) {
var distribDao,
cdnDao,
cdnSelector,
db,
httpServer,
loadBalancer;
async.series([
function connectToDatabase (next) {
database.connect(function (err, database) {
db = database;
next(err);
});
},
function loadDistributionConfig (next) {
// Pre-load all distribution config
distribDao = require('./libs/dao/DistributionDao')(db);
distribDao.once('ready', next);
distribDao.once('error', next);
},
function loadCDNs (next) {
// Pre-load all CDN config
cdnDao = require('./libs/dao/CDNDao')(db, distribDao);
cdnDao.once('ready', next);
cdnDao.once('error', next);
}
], function (err, results) {
if (!err) {
loadBalancer = new LoadBalancer(localConfig.loadBalancePeriod);
cdnSelector = new CDNSelector(distribDao, cdnDao, loadBalancer);
httpServer = new HttpServer(localConfig.port, cdnSelector, loggers.accesslog, tokenValidator);
httpServer.on('ready', function () {
var uid = parseInt(process.env.SUDO_UID);
if (uid) {
process.setuid(uid);
}
loggers.errorlog.info('Worker process ' + process.pid + ' started');
if (startupCompleteCallback) {
startupCompleteCallback(null, httpServer);
}
});
httpServer.on('redirection', function (cdn, distrib) {
// Tell the load balancer whenever a CDN is used.
loadBalancer.notifyCdnUsage(cdn, distrib);
});
httpServer.start();
} else {
if (startupCompleteCallback) {
startupCompleteCallback(err);
}
errorExit(err);
}
});
}
function startMaster(startupCompleteCallback) {
// Startup checks and pre-loading data
if (cluster.isMaster) {
// Master process
async.series([
function (callback) {
// Check that we can bind to the port
checkPort(localConfig.port, function (err, isAvailable) {
if (isAvailable) {
loggers.errorlog.info('Listening on port ' + localConfig.port);
callback();
} else {
callback(new Error('Cannot bind to port ' + localConfig.port + '. Is it already in use?', err));
}
});
},
function (callback) {
// Check that we can connect to the database, and
// create the database if necessary
database.connect(callback);
}
], function (err, results) {
if (startupCompleteCallback) {
startupCompleteCallback(err);
}
if (err) {
errorExit(err);
} else {
if (!process.env.CDNS_MANUAL_START) {
// Launch worker processes
var numCPUs = localConfig.workers || os.cpus().length;
loggers.errorlog.info('Starting cluster of ' + numCPUs + ' child processes.');
for (var i = 0; i < numCPUs; i += 1) {
cluster.fork();
}
// When a worker dies, respawn
cluster.on('exit', function (worker, code, signal) {
loggers.errorlog.error('Worker ' + worker.process.pid + ' died');
cluster.fork();
});
}
}
});
} else {
// Worker process
startWorker();
}
}
if (!process.env.CDNS_MANUAL_START) {
startMaster();
} else {
loggers.errorlog.info("CDNS_MANUAL_START is set, so we will not autostart");
}
// For integration tests...
module.exports = {
startMaster: startMaster,
startWorker: startWorker
}