webroar 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +10 -0
- data/README +116 -86
- data/doc/user-guide.html +2 -2
- data/doc/user-guide.txt +65 -65
- data/lib/command_runner.rb +5 -3
- data/src/head/wr_application.c +249 -294
- data/src/head/wr_application.h +28 -21
- data/src/head/wr_config.h +7 -1
- data/src/head/wr_connection.c +1 -1
- data/src/head/wr_controller.c +2 -4
- data/src/head/wr_request.c +1 -1
- data/src/head/wr_request.h +3 -3
- data/src/head/wr_resolver.c +2 -2
- data/src/head/wr_worker.c +16 -17
- data/src/ruby_lib/ruby_interface/version.rb +1 -1
- data/tasks/gem.rake +1 -1
- metadata +3 -3
data/src/head/wr_application.c
CHANGED
@@ -23,19 +23,37 @@ static unsigned int worker_count = 0;
|
|
23
23
|
|
24
24
|
/************** Private Functions ******************/
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
// Check whether application already exist
|
27
|
+
static inline wr_app_t* wr_app_exist(wr_svr_t *server, const char *app_name){
|
28
|
+
wr_app_t* app = server->apps, *tmp_app = NULL;
|
29
|
+
|
30
|
+
while(app) {
|
31
|
+
if(strcmp(app_name, app->conf->name.str)==0)
|
32
|
+
return app;
|
33
|
+
tmp_app = app;
|
34
|
+
app = app->next;
|
31
35
|
}
|
32
|
-
|
36
|
+
|
37
|
+
if(strcmp(app_name, WR_STATIC_FILE_SERVER_NAME) == 0){
|
38
|
+
return server->static_app;
|
39
|
+
}
|
40
|
+
|
41
|
+
return NULL;
|
42
|
+
}
|
33
43
|
|
34
|
-
|
44
|
+
// Check whether pending worker exist
|
45
|
+
static inline wr_pending_wkr_t* wr_pending_worker_exist(wr_app_t *app, const int pid){
|
46
|
+
int i;
|
47
|
+
for(i = 0 ; i < WR_QUEUE_SIZE(app->q_pending_workers); i++){
|
48
|
+
wr_pending_wkr_t* pending = wr_queue_fetch(app->q_pending_workers);
|
49
|
+
if(pending && *pending == pid) return pending;
|
50
|
+
wr_queue_insert(app->q_pending_workers, pending);
|
51
|
+
}
|
52
|
+
return NULL;
|
35
53
|
}
|
36
54
|
|
37
55
|
/** Callback function to add worker to application */
|
38
|
-
void
|
56
|
+
void wr_app_wkr_add_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
39
57
|
LOG_FUNCTION
|
40
58
|
wr_app_t* app = (wr_app_t*) w->data;
|
41
59
|
ev_timer_stop(loop, &app->t_add);
|
@@ -47,64 +65,86 @@ void wr_app_wrk_add_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
|
47
65
|
}
|
48
66
|
|
49
67
|
/** Callback function to add worker timeout */
|
50
|
-
void
|
68
|
+
void wr_app_wkr_add_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
51
69
|
LOG_FUNCTION
|
52
70
|
wr_app_t* app = (wr_app_t*) w->data;
|
53
71
|
char err_msg[512];
|
54
72
|
int err_msg_len = 0;
|
73
|
+
int pid = 0;
|
55
74
|
|
56
|
-
// Stop add timeout timer
|
75
|
+
// Stop add timeout timer and increament timeout counter
|
57
76
|
ev_timer_stop(loop, &app->t_add_timeout);
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
77
|
+
app->timeout_counter ++;
|
78
|
+
|
79
|
+
// Kill oldest pending worker
|
80
|
+
if(WR_QUEUE_SIZE(app->q_pending_workers) > 0) {
|
81
|
+
wr_pending_wkr_t *pending = wr_queue_fetch(app->q_pending_workers);
|
82
|
+
if(pending){
|
83
|
+
pid = *pending;
|
84
|
+
free(pending);
|
85
|
+
}
|
86
|
+
LOG_INFO("wr_app_wkr_add_timeout_cb: killing worker, pid = %d", pid);
|
64
87
|
if(pid > 0)
|
65
88
|
kill(pid ,SIGKILL);
|
66
|
-
LOG_DEBUG(DEBUG,"app->pending_wkr = %d", app->
|
67
|
-
app->
|
68
|
-
if(app->pending_wkr > 0) {
|
89
|
+
LOG_DEBUG(DEBUG,"app->pending_wkr = %d", WR_QUEUE_SIZE(app->q_pending_workers));
|
90
|
+
if(WR_QUEUE_SIZE(app->q_pending_workers) > 0) {
|
69
91
|
ev_timer_again(loop, &app->t_add_timeout);
|
70
92
|
}
|
71
93
|
|
72
94
|
// Update high load ratio
|
73
95
|
app->high_ratio = TOTAL_WORKER_COUNT(app) * WR_MAX_REQ_RATIO;
|
74
96
|
}
|
75
|
-
|
76
|
-
//
|
77
|
-
|
78
|
-
|
79
|
-
|
97
|
+
|
98
|
+
// If application restarted, rollback all the changes.
|
99
|
+
if(app->state == WR_APP_RESTART){
|
100
|
+
app->state = WR_APP_ACTIVE;
|
101
|
+
// Send error response
|
80
102
|
LOG_DEBUG(DEBUG,"Some problem occurred while starting Application %s.", app->conf->name.str);
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
103
|
+
if(app->ctl){
|
104
|
+
scgi_header_add(app->ctl->scgi, "STATUS", strlen("STATUS"), "ERROR", strlen("ERROR"));
|
105
|
+
err_msg_len = sprintf(err_msg,"The application could not be started due to the following error. Please refer '/var/log/webroar/%s.log' and the application log file for more details.", app->conf->name.str);
|
106
|
+
scgi_body_add(app->ctl->scgi, err_msg, err_msg_len);
|
107
|
+
wr_ctl_resp_write(app->ctl);
|
108
|
+
}
|
109
|
+
app->timeout_counter = 0;
|
85
110
|
app->ctl = NULL;
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
111
|
+
return;
|
112
|
+
}else if(app->state == WR_APP_NEW){
|
113
|
+
// Try out upto MAX timeout count
|
114
|
+
/*
|
115
|
+
if(WR_QUEUE_SIZE(app->q_pending_workers) == 0 && app->timeout_counter < WR_MAX_ADD_TIMEOUT_COUNTER){
|
116
|
+
wr_app_wkr_add(app);
|
117
|
+
}else{
|
118
|
+
*/
|
119
|
+
if(WR_QUEUE_SIZE(app->q_pending_workers) == 0){
|
120
|
+
// Send error response
|
121
|
+
LOG_DEBUG(DEBUG,"Some problem occurred while starting Application %s.", app->conf->name.str);
|
122
|
+
if(app->ctl){
|
123
|
+
scgi_header_add(app->ctl->scgi, "STATUS", strlen("STATUS"), "ERROR", strlen("ERROR"));
|
124
|
+
err_msg_len = sprintf(err_msg,"The application could not be started due to the following error. Please refer '/var/log/webroar/%s.log' and the application log file for more details.", app->conf->name.str);
|
125
|
+
scgi_body_add(app->ctl->scgi, err_msg, err_msg_len);
|
126
|
+
wr_ctl_resp_write(app->ctl);
|
127
|
+
}
|
128
|
+
app->timeout_counter = 0;
|
129
|
+
app->ctl = NULL;
|
130
|
+
wr_app_remove(app->svr, app->conf->name.str);
|
90
131
|
}
|
91
|
-
|
92
|
-
wr_app_remove(app->svr, app->conf->name.str);
|
93
|
-
} else if(app->in_use == TRUE && (TOTAL_WORKER_COUNT(app) < app->conf->min_worker || app->add_workers)) {
|
94
|
-
wr_app_wkr_add(app);
|
132
|
+
return;
|
95
133
|
}
|
134
|
+
|
135
|
+
wr_app_wkr_balance(app);
|
96
136
|
}
|
97
137
|
|
98
138
|
/** Callback function to remove worker from application */
|
99
|
-
void
|
139
|
+
void wr_app_wkr_remove_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
100
140
|
LOG_FUNCTION
|
101
141
|
wr_app_t* app = (wr_app_t*) w->data;
|
102
142
|
|
103
143
|
ev_timer_stop(loop, &app->t_remove);
|
104
144
|
|
105
|
-
// Following variable helps in removing unncecessary call to
|
106
|
-
int forecasted_count=app->
|
107
|
-
// Its a known bug - At any time app->active_worker should equals to app->
|
145
|
+
// Following variable helps in removing unncecessary call to wr_app_wkr_remove_cb
|
146
|
+
int forecasted_count=app->q_workers->q_count;
|
147
|
+
// Its a known bug - At any time app->active_worker should equals to app->q_workers->q_count
|
108
148
|
// Scenario: We are forking new worker due to high load and also increasing active worker count.
|
109
149
|
// It took some time to get register with Head, and actual queue count incremented after Head
|
110
150
|
// register the newly created worker. Now, mean while load goes down, and we are ready to remove the
|
@@ -117,15 +157,15 @@ void wr_app_wrk_remove_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
|
117
157
|
// when new worker is actually get registered with Head also, we reset active worker with
|
118
158
|
// application worker queue count, whenever worker is actually removed.
|
119
159
|
// TODO: Handle above bug properly.
|
120
|
-
LOG_DEBUG(DEBUG,"Pending_wkr = %d, app->
|
121
|
-
app->
|
122
|
-
if(app->
|
160
|
+
LOG_DEBUG(DEBUG,"Pending_wkr = %d, app->q_workers->q_count = %d",
|
161
|
+
WR_QUEUE_SIZE(app->q_pending_workers), WR_QUEUE_SIZE(app->q_workers));
|
162
|
+
if(app->q_workers->q_count > app->conf->min_worker) {
|
123
163
|
char cmd[WR_LONG_LONG_STR_LEN];
|
124
164
|
char pid_list[WR_LONG_LONG_STR_LEN], pid_c[WR_SHORT_STR_LEN];
|
125
165
|
int i,index;
|
126
166
|
i = 0;
|
127
|
-
index = (app->
|
128
|
-
wr_wkr_t *tmp_worker = (wr_wkr_t*)app->
|
167
|
+
index = (app->q_workers->q_front + i) % app->q_workers->q_max_size;
|
168
|
+
wr_wkr_t *tmp_worker = (wr_wkr_t*)app->q_workers->q_elements[index];
|
129
169
|
|
130
170
|
|
131
171
|
// Get pid of the worker consuming more resident memory
|
@@ -147,9 +187,9 @@ void wr_app_wrk_remove_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
|
147
187
|
sprintf(pid_c,"%d",tmp_worker->pid);
|
148
188
|
strcpy(pid_list, pid_c);
|
149
189
|
i++;
|
150
|
-
for(;i < app->
|
151
|
-
index = (app->
|
152
|
-
tmp_worker = (wr_wkr_t*)app->
|
190
|
+
for(;i < app->q_workers->q_count ; i++) {
|
191
|
+
index = (app->q_workers->q_front + i) % app->q_workers->q_max_size;
|
192
|
+
tmp_worker = (wr_wkr_t*)app->q_workers->q_elements[index];
|
153
193
|
sprintf(pid_c,",%d", tmp_worker->pid);
|
154
194
|
strcat(pid_list, pid_c);
|
155
195
|
}
|
@@ -168,12 +208,12 @@ void wr_app_wrk_remove_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
|
168
208
|
int flag = 1;
|
169
209
|
|
170
210
|
// Check for worker in list of free workers. If found remove it.
|
171
|
-
if(app->
|
211
|
+
if(app->q_free_workers->q_count > 0) {
|
172
212
|
LOG_DEBUG(DEBUG,", pid = %d find in free worker", pid);
|
173
213
|
//int i, index;
|
174
|
-
for( i = 0; i < app->
|
175
|
-
index = (app->
|
176
|
-
tmp_worker = (wr_wkr_t*)app->
|
214
|
+
for( i = 0; i < app->q_free_workers->q_count ; i++) {
|
215
|
+
index = (app->q_free_workers->q_front + i) % app->q_free_workers->q_max_size;
|
216
|
+
tmp_worker = (wr_wkr_t*)app->q_free_workers->q_elements[index];
|
177
217
|
if(tmp_worker->pid == pid) {
|
178
218
|
LOG_DEBUG(DEBUG,"Removing from free worker id=%d", tmp_worker->id);
|
179
219
|
forecasted_count--;
|
@@ -187,12 +227,12 @@ void wr_app_wrk_remove_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
|
187
227
|
|
188
228
|
// Check for worker in the list of all the worker. If found mark it as in-active.
|
189
229
|
// In-active worker will be removed once current request is processed.
|
190
|
-
if(flag && app->
|
230
|
+
if(flag && app->q_workers->q_count > 0) {
|
191
231
|
LOG_DEBUG(DEBUG,"pid = %d find in active worker", pid);
|
192
232
|
//int i, index;
|
193
|
-
for( i = 0; i < app->
|
194
|
-
index = (app->
|
195
|
-
tmp_worker = (wr_wkr_t*)app->
|
233
|
+
for( i = 0; i < app->q_workers->q_count ; i++) {
|
234
|
+
index = (app->q_workers->q_front + i) % app->q_workers->q_max_size;
|
235
|
+
tmp_worker = (wr_wkr_t*)app->q_workers->q_elements[index];
|
196
236
|
if(tmp_worker->pid == pid) {
|
197
237
|
forecasted_count--;
|
198
238
|
LOG_DEBUG(DEBUG,"Remove active status id = %d", tmp_worker->id);
|
@@ -217,7 +257,6 @@ static inline int wr_app_reload(wr_app_t *app){
|
|
217
257
|
wr_app_conf_t *app_conf;
|
218
258
|
short count;
|
219
259
|
|
220
|
-
app->restarted = FALSE;
|
221
260
|
// Remove an old application from the resolver list.
|
222
261
|
wr_req_resolver_remove(app->svr, app);
|
223
262
|
|
@@ -227,10 +266,13 @@ static inline int wr_app_reload(wr_app_t *app){
|
|
227
266
|
app->svr->err_msg);
|
228
267
|
if(app_conf == NULL){
|
229
268
|
LOG_DEBUG(WARN, "Error: %s",app->svr->err_msg);
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
269
|
+
if(app->ctl){
|
270
|
+
scgi_body_add(app->ctl->scgi, app->svr->err_msg, strlen(app->svr->err_msg));
|
271
|
+
scgi_header_add(app->ctl->scgi, "STATUS", strlen("STATUS"), "ERROR", strlen("ERROR"));
|
272
|
+
wr_ctl_resp_write(app->ctl);
|
273
|
+
}
|
274
|
+
app->state = WR_APP_ACTIVE;
|
275
|
+
return FALSE;
|
234
276
|
}
|
235
277
|
|
236
278
|
// Remove old application specification.
|
@@ -244,29 +286,24 @@ static inline int wr_app_reload(wr_app_t *app){
|
|
244
286
|
// Remove workers based on following logic:
|
245
287
|
// If all the workers are free keep a single worker to process the requests and remove all others.
|
246
288
|
// Else remove all the free workers.
|
247
|
-
count = (app->free_wkr_que->q_count == app->wkr_que->q_count ? 1 :0 );
|
248
289
|
|
249
|
-
LOG_DEBUG(DEBUG,"Free workers queue count is %d. Active worker count is %d.", WR_QUEUE_SIZE(app->
|
250
|
-
|
251
|
-
|
252
|
-
worker = (wr_wkr_t*)wr_queue_fetch(app->free_wkr_que);
|
290
|
+
LOG_DEBUG(DEBUG,"Free workers queue count is %d. Active worker count is %d.", WR_QUEUE_SIZE(app->q_free_workers), WR_QUEUE_SIZE(app->q_workers));
|
291
|
+
while(WR_QUEUE_SIZE(app->q_free_workers) > 0){
|
292
|
+
worker = (wr_wkr_t*)wr_queue_fetch(app->q_free_workers);
|
253
293
|
// The worker is already removed from free workers list so do not pass the flag.
|
254
294
|
wr_wkr_remove(worker, 0);
|
255
295
|
}
|
256
296
|
|
257
|
-
// Set the number of workers to be removed.
|
258
|
-
app->old_workers = WR_QUEUE_SIZE(app->wkr_que);
|
259
|
-
// Set the number of workers to be added.
|
260
|
-
app->add_workers = app->conf->min_worker;
|
261
297
|
// Mark all existing workers to OLD worker.
|
262
|
-
for(count = 0; count < app->
|
263
|
-
worker = (wr_wkr_t*)wr_queue_fetch(app->
|
264
|
-
wr_queue_insert(app->
|
298
|
+
for(count = 0; count < WR_QUEUE_SIZE(app->q_workers) ; count++) {
|
299
|
+
worker = (wr_wkr_t*)wr_queue_fetch(app->q_workers);
|
300
|
+
wr_queue_insert(app->q_workers, worker);
|
265
301
|
worker->state |= WR_WKR_OLD;
|
302
|
+
worker->state -= WR_WKR_ACTIVE;
|
266
303
|
}
|
267
304
|
|
268
|
-
|
269
|
-
return
|
305
|
+
app->state = WR_APP_RESTARTING;
|
306
|
+
return TRUE;
|
270
307
|
}
|
271
308
|
|
272
309
|
/*************** Application function definition *********/
|
@@ -277,31 +314,30 @@ void wr_app_free(wr_app_t* app) {
|
|
277
314
|
wr_app_t* tmp_app;
|
278
315
|
wr_wkr_t* worker;
|
279
316
|
|
280
|
-
//wr_application_print(app);
|
281
|
-
|
282
317
|
while(app) {
|
283
318
|
tmp_app = app->next;
|
284
|
-
app->
|
319
|
+
app->state = WR_APP_DESTROY;
|
285
320
|
LOG_DEBUG(4,"Destroying application %s...", app->conf->name.str);
|
286
|
-
LOG_DEBUG(DEBUG,"Worker count = %d", WR_QUEUE_SIZE(app->
|
321
|
+
LOG_DEBUG(DEBUG,"Worker count = %d", WR_QUEUE_SIZE(app->q_workers));
|
287
322
|
//Destroy workers
|
288
|
-
while(worker = (wr_wkr_t*)wr_queue_fetch(app->
|
323
|
+
while(worker = (wr_wkr_t*)wr_queue_fetch(app->q_workers)) {
|
289
324
|
if(app->svr->is_running==0)
|
290
325
|
worker->state |= WR_WKR_HANG;
|
291
326
|
wr_wkr_free(worker);
|
292
327
|
}
|
293
328
|
|
294
|
-
wr_queue_free(app->
|
295
|
-
wr_queue_free(app->
|
329
|
+
wr_queue_free(app->q_free_workers);
|
330
|
+
wr_queue_free(app->q_workers);
|
331
|
+
wr_queue_free(app->q_pending_workers);
|
296
332
|
|
297
333
|
wr_req_t *req;
|
298
|
-
WR_QUEUE_FETCH(app->
|
334
|
+
WR_QUEUE_FETCH(app->q_messages, req) ;
|
299
335
|
while(req) {
|
300
336
|
wr_conn_err_resp(req->conn, WR_HTTP_STATUS_500);
|
301
|
-
WR_QUEUE_FETCH(app->
|
337
|
+
WR_QUEUE_FETCH(app->q_messages, req) ;
|
302
338
|
}
|
303
339
|
|
304
|
-
wr_queue_free(app->
|
340
|
+
wr_queue_free(app->q_messages);
|
305
341
|
|
306
342
|
wr_req_resolver_remove(app->svr, app);
|
307
343
|
|
@@ -324,225 +360,159 @@ void wr_app_print(wr_app_t*app) {
|
|
324
360
|
|
325
361
|
/** Create worker for application */
|
326
362
|
int wr_app_wkr_add(wr_app_t *app) {
|
327
|
-
if(app->
|
363
|
+
if(WR_QUEUE_SIZE(app->q_pending_workers) < WR_QUEUE_MAX_SIZE(app->q_pending_workers)) {
|
328
364
|
int retval = wr_wkr_create(app->svr, app->conf);
|
329
365
|
if(retval > 0){
|
330
|
-
|
366
|
+
wr_pending_wkr_t *pending = wr_malloc(wr_pending_wkr_t);
|
367
|
+
*pending = retval;
|
368
|
+
wr_queue_insert(app->q_pending_workers, pending);
|
331
369
|
app->high_ratio = TOTAL_WORKER_COUNT(app) * WR_MAX_REQ_RATIO;
|
332
|
-
app->last_wkr_pid[app->pending_wkr-1] = retval;
|
333
370
|
ev_timer_again(app->svr->ebb_svr.loop, &app->t_add_timeout);
|
334
371
|
LOG_INFO("PID of created worker = %d, Rails application=%s",
|
335
|
-
|
336
|
-
return
|
372
|
+
retval, app->conf->path.str);
|
373
|
+
return TRUE;
|
337
374
|
}else{
|
338
375
|
LOG_ERROR(SEVERE,"Could not fork process to start new worker.");
|
339
376
|
}
|
340
377
|
}
|
341
|
-
return
|
378
|
+
return FALSE;
|
342
379
|
}
|
343
380
|
|
344
381
|
/** Insert application based on application configuration */
|
345
382
|
static int wr_app_insert(wr_svr_t* server, wr_app_conf_t* config, wr_ctl_t *ctl) {
|
346
383
|
LOG_FUNCTION
|
347
384
|
wr_app_t* app = wr_malloc(wr_app_t);
|
348
|
-
short is_static_server = 0;
|
349
385
|
|
350
386
|
if(!app) {
|
351
387
|
LOG_ERROR(WARN, "%s() application object allocation failed. Returning ...", __FUNCTION__);
|
352
|
-
return
|
388
|
+
return FALSE;
|
353
389
|
}
|
354
390
|
|
355
|
-
|
356
|
-
|
357
|
-
|
391
|
+
// Queue size is WR_ALLOWED_MAX_WORKERS + 1 to accommodate temporary extra
|
392
|
+
// worker, created during application restart
|
393
|
+
app->q_free_workers = wr_queue_new(WR_ALLOWED_MAX_WORKERS + 1);
|
394
|
+
app->q_workers = wr_queue_new(WR_ALLOWED_MAX_WORKERS + 1);
|
395
|
+
app->q_pending_workers = wr_queue_new(WR_MAX_PENDING_WKR);
|
358
396
|
|
359
|
-
|
360
|
-
app->free_wkr_que = wr_queue_new(WR_ALLOWED_MAX_WORKERS + 1);
|
361
|
-
app->wkr_que = wr_queue_new(WR_ALLOWED_MAX_WORKERS + 1);
|
362
|
-
app->msg_que = wr_queue_new(WR_MSG_QUE_SIZE);
|
397
|
+
app->q_messages = wr_queue_new(WR_MSG_QUE_SIZE);
|
363
398
|
|
364
|
-
if(
|
365
|
-
|
366
|
-
app->msg_que == NULL) {
|
399
|
+
if(app->q_workers == NULL || app->q_pending_workers == NULL ||
|
400
|
+
app->q_free_workers == NULL || app->q_messages == NULL) {
|
367
401
|
free(app);
|
368
402
|
app = NULL;
|
369
403
|
LOG_ERROR(WARN, "application object initialization failed. Returning ...");
|
370
|
-
return
|
404
|
+
return FALSE;
|
371
405
|
}
|
406
|
+
|
372
407
|
app->svr = server;
|
373
408
|
app->conf = config;
|
374
409
|
app->ctl = ctl;
|
410
|
+
app->state = WR_APP_NEW;
|
411
|
+
app->timeout_counter = 0;
|
412
|
+
app->high_ratio = 0;
|
413
|
+
app->t_add.data = app->t_remove.data = app->t_add_timeout.data = app;
|
414
|
+
|
375
415
|
/* set application object in control, it would be used at time of freeing control object */
|
376
|
-
if(ctl)
|
377
|
-
|
378
|
-
|
379
|
-
|
416
|
+
if(ctl) ctl->app = app;
|
417
|
+
|
418
|
+
if(strcmp(config->name.str, WR_STATIC_FILE_SERVER_NAME) == 0){
|
419
|
+
app->next = NULL;
|
420
|
+
server->static_app = app;
|
421
|
+
}else{
|
380
422
|
wr_req_resolver_add(server, app, config);
|
381
423
|
app->next = server->apps;
|
382
424
|
server->apps = app;
|
383
|
-
}else{
|
384
|
-
app->next = NULL;
|
385
|
-
server->static_app = app;
|
386
425
|
}
|
387
426
|
|
388
|
-
app->t_add
|
389
|
-
|
390
|
-
ev_timer_init (&app->
|
391
|
-
ev_timer_init (&app->t_remove, wr_app_wrk_remove_cb, 0., WR_LOW_LOAD_LIMIT);
|
392
|
-
ev_timer_init (&app->t_add_timeout, wr_app_wrk_add_timeout_cb, 0., WR_WKR_ADD_TIMEOUT);
|
427
|
+
ev_timer_init (&app->t_add, wr_app_wkr_add_cb, 0., WR_HIGH_LOAD_LIMIT);
|
428
|
+
ev_timer_init (&app->t_remove, wr_app_wkr_remove_cb, 0., WR_LOW_LOAD_LIMIT);
|
429
|
+
ev_timer_init (&app->t_add_timeout, wr_app_wkr_add_timeout_cb, 0., WR_WKR_ADD_TIMEOUT);
|
393
430
|
|
394
|
-
//app->next = server->apps;
|
395
|
-
//server->apps = app;
|
396
431
|
LOG_DEBUG(4,"%s() Application Added:%s", __FUNCTION__, config->name.str);
|
397
432
|
|
398
|
-
app
|
399
|
-
|
400
|
-
|
401
|
-
app->old_workers = 0;
|
402
|
-
app->add_workers = 0;
|
403
|
-
|
404
|
-
int i;
|
405
|
-
for(i = 0; i < WR_MAX_PENDING_WKR ; i ++) {
|
406
|
-
app->last_wkr_pid[i] = 0;
|
407
|
-
}
|
408
|
-
|
409
|
-
/** Creating workers */
|
410
|
-
for(i=0; i < config->min_worker; i++) {
|
411
|
-
//Create a new Worker
|
412
|
-
wr_app_wkr_add(app);
|
413
|
-
// int pid = wr_wkr_create(server, config);
|
414
|
-
// LOG_DEBUG(DEBUG,"Rails application=%s", config->path.str);
|
415
|
-
// LOG_DEBUG(4,"PID of created process is %i",pid);
|
416
|
-
}
|
417
|
-
|
418
|
-
//app->high_ratio = TOTAL_WORKER_COUNT(app) * WR_MAX_REQ_RATIO;
|
419
|
-
app->low_ratio = TOTAL_WORKER_COUNT(app) * WR_MIN_REQ_RATIO;
|
420
|
-
return 0;
|
433
|
+
wr_app_wkr_balance(app);
|
434
|
+
|
435
|
+
return TRUE;
|
421
436
|
}
|
422
437
|
|
423
|
-
/**
|
424
|
-
void
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
LOG_DEBUG(DEBUG, "Number of add workers is %d.", app->add_workers);
|
431
|
-
app->add_workers --;
|
438
|
+
/** Balance number of workers */
|
439
|
+
void wr_app_wkr_balance(wr_app_t *app){
|
440
|
+
// Maintain minimum number of workers
|
441
|
+
//while(TOTAL_WORKER_COUNT(app) < app->conf->min_worker && app->timeout_counter < WR_MAX_ADD_TIMEOUT_COUNTER){
|
442
|
+
while(TOTAL_WORKER_COUNT(app) < app->conf->min_worker){
|
443
|
+
if(wr_app_wkr_add(app) == FALSE) break;
|
444
|
+
app->low_ratio = TOTAL_WORKER_COUNT(app) * WR_MIN_REQ_RATIO;
|
432
445
|
}
|
433
446
|
|
434
|
-
|
435
|
-
|
436
|
-
|
447
|
+
if(WR_QUEUE_SIZE(app->q_workers) >= app->conf->min_worker && app->state == WR_APP_RESTART)
|
448
|
+
app->state == WR_APP_ACTIVE;
|
449
|
+
|
450
|
+
// Create worker if application is high loaded
|
451
|
+
/*
|
452
|
+
if(TOTAL_WORKER_COUNT(app) < app->conf->max_worker && WR_QUEUE_SIZE(app->q_messages) > app->high_ratio){
|
437
453
|
wr_app_wkr_add(app);
|
438
|
-
}else{
|
439
|
-
if(app->old_workers){
|
440
|
-
short count, i;
|
441
|
-
// Remove all the old workers, if there is no more workers to add.
|
442
|
-
LOG_DEBUG(DEBUG, "Number of old workers is %d.", app->old_workers);
|
443
|
-
count = WR_QUEUE_SIZE(app->wkr_que);
|
444
|
-
for( i = 0 ; i < count ; i ++){
|
445
|
-
worker = (wr_wkr_t*) wr_queue_fetch(app->wkr_que);
|
446
|
-
wr_queue_insert(app->wkr_que, worker);
|
447
|
-
if(worker->state & WR_WKR_OLD){
|
448
|
-
// Pass flag to remove worker from the worker free list.
|
449
|
-
wr_wkr_remove(worker, 1);
|
450
|
-
app->old_workers --;
|
451
|
-
}
|
452
|
-
}
|
453
|
-
app->old_workers = 0;
|
454
|
-
}
|
455
|
-
|
456
|
-
// Add worker if total number of worker is less than minimum number of workes.
|
457
|
-
if(TOTAL_WORKER_COUNT(app) < app->conf->min_worker){
|
458
|
-
LOG_DEBUG(DEBUG, "Application does not have minimum number of workes.");
|
459
|
-
wr_app_wkr_add(app);
|
460
|
-
}
|
461
|
-
return;
|
462
|
-
}
|
463
|
-
|
464
|
-
// Remove old worker.
|
465
|
-
if(app->old_workers){
|
466
|
-
short count, i;
|
467
|
-
LOG_DEBUG(DEBUG, "Number of old workers is %d.", app->old_workers);
|
468
|
-
count = WR_QUEUE_SIZE(app->wkr_que);
|
469
|
-
for( i = 0 ; i < count ; i ++){
|
470
|
-
worker = (wr_wkr_t*) wr_queue_fetch(app->wkr_que);
|
471
|
-
wr_queue_insert(app->wkr_que, worker);
|
472
|
-
LOG_DEBUG(DEBUG,"Worker PID is %d and state is %d.", worker->pid, worker->state);
|
473
|
-
if(worker->state & WR_WKR_OLD){
|
474
|
-
// Pass flag to remove worker from the worker free list.
|
475
|
-
wr_wkr_remove(worker, 1);
|
476
|
-
app->old_workers --;
|
477
|
-
break;
|
478
|
-
}
|
479
|
-
}
|
480
454
|
}
|
455
|
+
*/
|
481
456
|
}
|
482
457
|
|
483
458
|
/** Add newly created worker to application */
|
484
|
-
int
|
459
|
+
int wr_app_wkr_insert(wr_svr_t *server, wr_wkr_t *worker,const wr_ctl_msg_t *ctl_msg) {
|
485
460
|
LOG_FUNCTION
|
486
|
-
wr_app_t* app = server->apps;
|
487
461
|
const char* app_name = ctl_msg->msg.wkr.app_name.str;
|
462
|
+
wr_app_t* app = wr_app_exist(server, app_name);
|
488
463
|
|
489
|
-
if(
|
490
|
-
|
464
|
+
if(app == NULL){
|
465
|
+
LOG_ERROR(SEVERE, "Either queue is full or Baseuri is not matched");
|
466
|
+
scgi_body_add(worker->ctl->scgi, "Either queue is full or Baseuri is not matched.",
|
467
|
+
strlen("Either queue is full or Baseuri is not matched."));
|
468
|
+
return -1;
|
491
469
|
}
|
492
470
|
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
if(i == app->pending_wkr) {
|
505
|
-
scgi_body_add(worker->ctl->scgi, "Either worker add timeout or worker PID does not match.",
|
506
|
-
strlen("Either worker add timeout or worker PID does not match."));
|
507
|
-
return -1;
|
508
|
-
}
|
509
|
-
|
510
|
-
for(; i < app->pending_wkr ; i++) {
|
511
|
-
app->last_wkr_pid[i] = app->last_wkr_pid[i+1];
|
512
|
-
}
|
513
|
-
app->last_wkr_pid[i] = 0;
|
514
|
-
app->pending_wkr --;
|
471
|
+
LOG_DEBUG(DEBUG,"app->a_config->max_worker = %d, app->q_workers->q_count =%d", app->conf->max_worker, WR_QUEUE_SIZE(app->q_workers));
|
472
|
+
LOG_DEBUG(DEBUG, "Application name = %s, Application->config->name =%s", app_name, app->conf->name.str );
|
473
|
+
|
474
|
+
if(app->conf->max_worker > WR_QUEUE_SIZE(app->q_workers) || app->state == WR_APP_RESTART) {
|
475
|
+
wr_pending_wkr_t *pending = wr_pending_worker_exist(app, worker->pid);
|
476
|
+
|
477
|
+
if(pending == NULL){
|
478
|
+
scgi_body_add(worker->ctl->scgi, "Either worker add timeout or worker PID does not match.",
|
479
|
+
strlen("Either worker add timeout or worker PID does not match."));
|
480
|
+
return -1;
|
481
|
+
}
|
515
482
|
|
483
|
+
worker->id = ++worker_count;
|
484
|
+
worker->app = app;
|
485
|
+
if(!(worker->state & WR_WKR_ACTIVE)) worker->state += WR_WKR_ACTIVE;
|
516
486
|
|
517
|
-
|
518
|
-
worker->app = app;
|
487
|
+
app->timeout_counter = 0;
|
519
488
|
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
if(app->
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
wr_ctl_resp_write(app->ctl);
|
531
|
-
app->ctl = NULL;
|
532
|
-
}
|
533
|
-
}
|
534
|
-
|
535
|
-
if(app->restarted == TRUE){
|
536
|
-
return wr_app_reload(app);
|
489
|
+
if(WR_QUEUE_SIZE(app->q_pending_workers) <= 0)
|
490
|
+
ev_timer_stop(app->svr->ebb_svr.loop, &app->t_add_timeout);
|
491
|
+
|
492
|
+
if(app->state == WR_APP_RESTART){
|
493
|
+
if(wr_app_reload(app) == FALSE) return -1;
|
494
|
+
if(app->ctl) {
|
495
|
+
LOG_DEBUG(DEBUG,"Send OK status");
|
496
|
+
scgi_header_add(app->ctl->scgi, "STATUS", strlen("STATUS"), "OK", strlen("OK"));
|
497
|
+
wr_ctl_resp_write(app->ctl);
|
498
|
+
app->ctl = NULL;
|
537
499
|
}
|
538
|
-
|
539
500
|
return 0;
|
540
501
|
}
|
541
|
-
|
502
|
+
|
503
|
+
if(app->state == WR_APP_NEW){
|
504
|
+
if(app->ctl) {
|
505
|
+
LOG_DEBUG(DEBUG,"Send OK status");
|
506
|
+
scgi_header_add(app->ctl->scgi, "STATUS", strlen("STATUS"), "OK", strlen("OK"));
|
507
|
+
wr_ctl_resp_write(app->ctl);
|
508
|
+
app->ctl = NULL;
|
509
|
+
}
|
510
|
+
|
511
|
+
app->state = WR_APP_ACTIVE;
|
512
|
+
}
|
513
|
+
return 0;
|
542
514
|
}
|
543
|
-
|
544
|
-
scgi_body_add(worker->ctl->scgi, "Either queue is full or Baseuri is not matched.",
|
545
|
-
strlen("Either queue is full or Baseuri is not matched."));
|
515
|
+
|
546
516
|
return -1;
|
547
517
|
}
|
548
518
|
|
@@ -580,7 +550,7 @@ int wr_app_remove(wr_svr_t* server, const char* app_name) {
|
|
580
550
|
/** Check load balance to add the worker */
|
581
551
|
void wr_app_chk_load_to_add_wkr(wr_app_t *app) {
|
582
552
|
if(TOTAL_WORKER_COUNT(app) < app->conf->max_worker) {
|
583
|
-
if(app->
|
553
|
+
if(app->q_messages->q_count > app->high_ratio) {
|
584
554
|
if(!ev_is_active(&app->t_add)) {
|
585
555
|
LOG_DEBUG(DEBUG,"%s() Timer set", __FUNCTION__);
|
586
556
|
ev_timer_again(app->svr->ebb_svr.loop, &app->t_add);
|
@@ -595,8 +565,8 @@ void wr_app_chk_load_to_add_wkr(wr_app_t *app) {
|
|
595
565
|
/** Check load balance to remove the worker */
|
596
566
|
void wr_app_chk_load_to_remove_wkr(wr_app_t *app) {
|
597
567
|
//Check load
|
598
|
-
if(WR_QUEUE_SIZE(app->
|
599
|
-
if(app->
|
568
|
+
if(WR_QUEUE_SIZE(app->q_workers) > app->conf->min_worker) {
|
569
|
+
if(app->q_messages->q_count < app->low_ratio) {
|
600
570
|
if(!ev_is_active(&app->t_remove)) {
|
601
571
|
LOG_DEBUG(DEBUG,"%s() Timer set", __FUNCTION__);
|
602
572
|
ev_timer_again(app->svr->ebb_svr.loop, &app->t_remove);
|
@@ -619,34 +589,27 @@ void wr_app_init(wr_svr_t *server) {
|
|
619
589
|
}
|
620
590
|
}
|
621
591
|
|
622
|
-
/**
|
592
|
+
/** Apllication add callback */
|
593
|
+
/* Deploy an application on the server */
|
623
594
|
void wr_app_add_cb(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg) {
|
624
595
|
LOG_FUNCTION
|
625
596
|
|
626
597
|
wr_svr_t* server = ctl->svr;
|
627
598
|
wr_app_conf_t* app_conf = NULL;
|
628
|
-
wr_app_t* app = server
|
629
|
-
|
630
|
-
while(app) {
|
631
|
-
if(strcmp(ctl_msg->msg.app.app_name.str, app->conf->name.str)==0)
|
632
|
-
break;
|
633
|
-
tmp_app = app;
|
634
|
-
app = app->next;
|
635
|
-
}
|
636
|
-
ctl->svr->err_msg[0] = 0;
|
637
|
-
if(app) {
|
638
|
-
/* set application object in control, it would be used at time of freeing control object */
|
639
|
-
ctl->app = app;
|
640
|
-
sprintf(ctl->svr->err_msg, "Application '%s' is already running.", ctl_msg->msg.app.app_name.str);
|
641
|
-
}
|
599
|
+
wr_app_t* app = wr_app_exist(server, ctl_msg->msg.app.app_name.str);
|
642
600
|
|
643
|
-
|
644
|
-
|
601
|
+
// Reset the error message
|
602
|
+
ctl->svr->err_msg[0] = 0;
|
603
|
+
if(app){
|
604
|
+
/* set application object in control, it would be used at time of freeing control object */
|
605
|
+
ctl->app = app;
|
606
|
+
sprintf(ctl->svr->err_msg, "Application '%s' is already running.", ctl_msg->msg.app.app_name.str);
|
607
|
+
}else if(ctl && server && server->conf) {
|
608
|
+
app_conf = wr_conf_app_read(server->conf,
|
645
609
|
ctl_msg->msg.app.app_name.str,
|
646
610
|
ctl->svr->err_msg);
|
647
611
|
if(app_conf!=NULL) {
|
648
|
-
if(wr_app_insert(ctl->svr, app_conf, ctl)
|
649
|
-
return;
|
612
|
+
if(wr_app_insert(ctl->svr, app_conf, ctl) == TRUE) return;
|
650
613
|
} else if(ctl->svr->err_msg[0] == 0) {
|
651
614
|
sprintf(ctl->svr->err_msg, "Application '%s' is not found.", ctl_msg->msg.app.app_name.str);
|
652
615
|
}
|
@@ -670,25 +633,17 @@ void wr_app_remove_cb(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg) {
|
|
670
633
|
}
|
671
634
|
|
672
635
|
/** Allication reload callback */
|
673
|
-
void wr_app_reload_cb(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg)
|
636
|
+
void wr_app_reload_cb(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg){
|
674
637
|
LOG_FUNCTION
|
675
|
-
wr_app_t *app = ctl->svr->apps;
|
676
638
|
wr_app_conf_t* app_config = NULL;
|
677
|
-
|
678
|
-
// Find the application.
|
679
|
-
while(app) {
|
680
|
-
if(strcmp(ctl_msg->msg.app.app_name.str, app->conf->name.str)==0){
|
681
|
-
/* set application object in control, it would be used at time of freeing control object */
|
682
|
-
ctl->app = app;
|
683
|
-
break;
|
684
|
-
}
|
685
|
-
app = app->next;
|
686
|
-
}
|
639
|
+
wr_app_t *app = wr_app_exist(ctl->svr, ctl_msg->msg.app.app_name.str);
|
687
640
|
|
688
641
|
// Read new application configuration.
|
689
642
|
app_config = wr_conf_app_update(ctl->svr->conf,
|
690
|
-
|
691
|
-
|
643
|
+
ctl_msg->msg.app.app_name.str,
|
644
|
+
ctl->svr->err_msg);
|
645
|
+
|
646
|
+
LOG_INFO("Reload the application %s", ctl_msg->msg.app.app_name.str);
|
692
647
|
// Report error on not getting the application configuration.
|
693
648
|
if(app_config == NULL){
|
694
649
|
LOG_ERROR(WARN, "Error: %s",ctl->svr->err_msg);
|
@@ -702,26 +657,26 @@ void wr_app_reload_cb(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg) {
|
|
702
657
|
}
|
703
658
|
return;
|
704
659
|
}
|
705
|
-
|
706
|
-
if(app)
|
660
|
+
|
661
|
+
if(app){
|
707
662
|
int i;
|
708
663
|
wr_app_conf_t *tmp_app_conf = app->conf;
|
709
664
|
// Set variables to restart the application.
|
710
665
|
LOG_DEBUG(DEBUG,"Set variables to restart an existing application.");
|
711
666
|
app->conf = app_config;
|
712
|
-
app->
|
713
|
-
app->
|
714
|
-
|
715
|
-
|
716
|
-
app->last_wkr_pid[i] = 0;
|
667
|
+
app->state = WR_APP_RESTART;
|
668
|
+
while(WR_QUEUE_SIZE(app->q_pending_workers) > 0){
|
669
|
+
wr_pending_wkr_t* pending = wr_queue_fetch(app->q_pending_workers);
|
670
|
+
free(pending);
|
717
671
|
}
|
672
|
+
|
718
673
|
app->ctl = ctl;
|
719
674
|
LOG_DEBUG(4,"%s() Application Added:%s", __FUNCTION__, app->conf->name.str);
|
720
|
-
|
675
|
+
|
721
676
|
// Add single worker with updated application.
|
722
677
|
LOG_DEBUG(DEBUG, "Add first worker on application restart.");
|
723
678
|
wr_app_wkr_add(app);
|
724
|
-
|
679
|
+
|
725
680
|
// Replace the application configuration with older configuration object.
|
726
681
|
wr_conf_app_replace(app->svr->conf, tmp_app_conf);
|
727
682
|
app->conf = tmp_app_conf;
|
@@ -731,13 +686,13 @@ void wr_app_reload_cb(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg) {
|
|
731
686
|
LOG_ERROR(WARN,"Aapplication %s didn't found in list", ctl_msg->msg.app.app_name.str);
|
732
687
|
sprintf(ctl->svr->err_msg, "Application '%s' is not found.", ctl_msg->msg.app.app_name.str);
|
733
688
|
scgi_body_add(ctl->scgi,
|
734
|
-
|
735
|
-
|
736
|
-
if(wr_app_insert(ctl->svr, app_config, ctl) ==
|
737
|
-
return;
|
689
|
+
"Couldn't remove application. But trying to start application.",
|
690
|
+
strlen("Couldn't remove application. But trying to start application."));
|
691
|
+
if(wr_app_insert(ctl->svr, app_config, ctl) == TRUE) return;
|
738
692
|
}
|
739
693
|
|
740
694
|
// Return ERROR status.
|
741
695
|
scgi_header_add(ctl->scgi, "STATUS", strlen("STATUS"), "ERROR", strlen("ERROR"));
|
742
696
|
wr_ctl_resp_write(ctl);
|
743
697
|
}
|
698
|
+
|