Show More
@@ -8,7 +8,91 b'' | |||
|
8 | 8 | host = 0.0.0.0 |
|
9 | 9 | port = 9900 |
|
10 | 10 | |
|
11 | ########################################################### | |
|
12 | ## WAITRESS WSGI SERVER - Recommended for Development #### | |
|
13 | ########################################################### | |
|
14 | ||
|
11 | 15 | use = egg:waitress#main |
|
16 | ## number of worker threads | |
|
17 | threads = 5 | |
|
18 | ## MAX BODY SIZE 100GB | |
|
19 | max_request_body_size = 107374182400 | |
|
20 | ## Use poll instead of select, fixes file descriptors limits problems. | |
|
21 | ## May not work on old windows systems. | |
|
22 | asyncore_use_poll = true | |
|
23 | ||
|
24 | ||
|
25 | ########################## | |
|
26 | ## GUNICORN WSGI SERVER ## | |
|
27 | ########################## | |
|
28 | ## run with gunicorn --log-config vcsserver.ini --paste vcsserver.ini | |
|
29 | ||
|
30 | #use = egg:gunicorn#main | |
|
31 | ## Sets the number of process workers. More workers means more concurrent connections | |
|
32 | ## RhodeCode can handle at the same time. Each additional worker also it increases | |
|
33 | ## memory usage as each has it's own set of caches. | |
|
34 | ## Recommended value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers, but no more | |
|
35 | ## than 8-10 unless for really big deployments .e.g 700-1000 users. | |
|
36 | ## `instance_id = *` must be set in the [app:main] section below (which is the default) | |
|
37 | ## when using more than 1 worker. | |
|
38 | #workers = 2 | |
|
39 | ||
|
40 | ## Gunicorn access log level | |
|
41 | #loglevel = info | |
|
42 | ||
|
43 | ## process name visible in process list | |
|
44 | #proc_name = rhodecode_vcsserver | |
|
45 | ||
|
46 | ## type of worker class, currently `sync` is the only option allowed. | |
|
47 | #worker_class = sync | |
|
48 | ||
|
49 | ## The maximum number of simultaneous clients. Valid only for Gevent | |
|
50 | #worker_connections = 10 | |
|
51 | ||
|
52 | ## max number of requests that worker will handle before being gracefully | |
|
53 | ## restarted, could prevent memory leaks | |
|
54 | #max_requests = 1000 | |
|
55 | #max_requests_jitter = 30 | |
|
56 | ||
|
57 | ## amount of time a worker can spend with handling a request before it | |
|
58 | ## gets killed and restarted. Set to 6hrs | |
|
59 | #timeout = 21600 | |
|
60 | ||
|
61 | ## The maximum size of HTTP request line in bytes. | |
|
62 | ## 0 for unlimited | |
|
63 | #limit_request_line = 0 | |
|
64 | ||
|
65 | ## Limit the number of HTTP headers fields in a request. | |
|
66 | ## By default this value is 100 and can't be larger than 32768. | |
|
67 | #limit_request_fields = 32768 | |
|
68 | ||
|
69 | ## Limit the allowed size of an HTTP request header field. | |
|
70 | ## Value is a positive number or 0. | |
|
71 | ## Setting it to 0 will allow unlimited header field sizes. | |
|
72 | #limit_request_field_size = 0 | |
|
73 | ||
|
74 | ## Timeout for graceful workers restart. | |
|
75 | ## After receiving a restart signal, workers have this much time to finish | |
|
76 | ## serving requests. Workers still alive after the timeout (starting from the | |
|
77 | ## receipt of the restart signal) are force killed. | |
|
78 | #graceful_timeout = 3600 | |
|
79 | ||
|
80 | # The number of seconds to wait for requests on a Keep-Alive connection. | |
|
81 | # Generally set in the 1-5 seconds range. | |
|
82 | #keepalive = 2 | |
|
83 | ||
|
84 | ## Maximum memory usage that each worker can use before it will receive a | |
|
85 | ## graceful restart signal, e.g 10MB = 10485760 (10 * 1024 * 1024) | |
|
86 | # 0 = memory monitoring is disabled | |
|
87 | #memory_max_usage = 0 | |
|
88 | ||
|
89 | ## How often in seconds to check for memory usage for each gunicorn worker | |
|
90 | #memory_usage_check_interval = 60 | |
|
91 | ||
|
92 | ## Threshold value for which we don't recycle worker if GarbageCollection | |
|
93 | ## frees up enough resources. Before each restart we try to run GC on worker | |
|
94 | ## in case we get enough free memory after that, restart will not happen. | |
|
95 | #memory_usage_recovery_threshold = 0.8 | |
|
12 | 96 | |
|
13 | 97 | |
|
14 | 98 | [app:main] |
@@ -13,9 +13,10 b' available post the .ini config.' | |||
|
13 | 13 | |
|
14 | 14 | """ |
|
15 | 15 | |
|
16 | import gc | |
|
17 | import os | |
|
18 | import sys | |
|
16 | 19 | import math |
|
17 | import gc | |
|
18 | import sys | |
|
19 | 20 | import time |
|
20 | 21 | import threading |
|
21 | 22 | import traceback |
@@ -30,32 +31,7 b' def get_workers():' | |||
|
30 | 31 | # GLOBAL |
|
31 | 32 | errorlog = '-' |
|
32 | 33 | accesslog = '-' |
|
33 | loglevel = 'info' | |
|
34 | 34 | |
|
35 | # SECURITY | |
|
36 | ||
|
37 | # The maximum size of HTTP request line in bytes. | |
|
38 | # 0 for unlimited | |
|
39 | limit_request_line = 0 | |
|
40 | ||
|
41 | # Limit the number of HTTP headers fields in a request. | |
|
42 | # By default this value is 100 and can't be larger than 32768. | |
|
43 | limit_request_fields = 32768 | |
|
44 | ||
|
45 | # Limit the allowed size of an HTTP request header field. | |
|
46 | # Value is a positive number or 0. | |
|
47 | # Setting it to 0 will allow unlimited header field sizes. | |
|
48 | limit_request_field_size = 0 | |
|
49 | ||
|
50 | # Timeout for graceful workers restart. | |
|
51 | # After receiving a restart signal, workers have this much time to finish | |
|
52 | # serving requests. Workers still alive after the timeout (starting from the | |
|
53 | # receipt of the restart signal) are force killed. | |
|
54 | graceful_timeout = 60 * 60 | |
|
55 | ||
|
56 | # The number of seconds to wait for requests on a Keep-Alive connection. | |
|
57 | # Generally set in the 1-5 seconds range. | |
|
58 | keepalive = 2 | |
|
59 | 35 | |
|
60 | 36 | # SERVER MECHANICS |
|
61 | 37 | # None == system temp dir |
@@ -70,15 +46,6 b' access_log_format = (' | |||
|
70 | 46 | # self adjust workers based on CPU count |
|
71 | 47 | # workers = get_workers() |
|
72 | 48 | |
|
73 | # n * 1024 * 0124 == n MBs, 0 = memory monitoring is disabled | |
|
74 | MAX_MEMORY_USAGE = 0 * 1024 * 1024 | |
|
75 | ||
|
76 | # How often in seconds to check for memory usage | |
|
77 | MEMORY_USAGE_CHECK_INTERVAL = 30 | |
|
78 | ||
|
79 | # If a gc brings us back below this threshold, we can avoid termination. | |
|
80 | MEMORY_USAGE_RECOVERY_THRESHOLD = MAX_MEMORY_USAGE * 0.8 | |
|
81 | ||
|
82 | 49 | |
|
83 | 50 | def _get_process_rss(pid=None): |
|
84 | 51 | try: |
@@ -92,8 +59,22 b' def _get_process_rss(pid=None):' | |||
|
92 | 59 | return None |
|
93 | 60 | |
|
94 | 61 | |
|
95 | def _time_with_offset(): | |
|
96 | return time.time() - random.randint(0, MEMORY_USAGE_CHECK_INTERVAL/2.0) | |
|
62 | def _get_config(ini_path): | |
|
63 | ||
|
64 | try: | |
|
65 | import configparser | |
|
66 | except ImportError: | |
|
67 | import ConfigParser as configparser | |
|
68 | try: | |
|
69 | config = configparser.ConfigParser() | |
|
70 | config.read(ini_path) | |
|
71 | return config | |
|
72 | except Exception: | |
|
73 | return None | |
|
74 | ||
|
75 | ||
|
76 | def _time_with_offset(memory_usage_check_interval): | |
|
77 | return time.time() - random.randint(0, memory_usage_check_interval/2.0) | |
|
97 | 78 | |
|
98 | 79 | |
|
99 | 80 | def pre_fork(server, worker): |
@@ -101,10 +82,37 b' def pre_fork(server, worker):' | |||
|
101 | 82 | |
|
102 | 83 | |
|
103 | 84 | def post_fork(server, worker): |
|
104 | server.log.info("<%s> WORKER spawned", worker.pid) | |
|
85 | ||
|
86 | # memory spec defaults | |
|
87 | _memory_max_usage = 0 | |
|
88 | _memory_usage_check_interval = 60 | |
|
89 | _memory_usage_recovery_threshold = 0.8 | |
|
90 | ||
|
91 | ini_path = os.path.abspath(server.cfg.paste) | |
|
92 | conf = _get_config(ini_path) | |
|
93 | if conf and 'server:main' in conf: | |
|
94 | section = conf['server:main'] | |
|
95 | ||
|
96 | if section.get('memory_max_usage'): | |
|
97 | _memory_max_usage = int(section.get('memory_max_usage')) | |
|
98 | if section.get('memory_usage_check_interval'): | |
|
99 | _memory_usage_check_interval = int(section.get('memory_usage_check_interval')) | |
|
100 | if section.get('memory_usage_recovery_threshold'): | |
|
101 | _memory_usage_recovery_threshold = float(section.get('memory_usage_recovery_threshold')) | |
|
102 | ||
|
103 | worker._memory_max_usage = _memory_max_usage | |
|
104 | worker._memory_usage_check_interval = _memory_usage_check_interval | |
|
105 | worker._memory_usage_recovery_threshold = _memory_usage_recovery_threshold | |
|
106 | ||
|
105 | 107 | # register memory last check time, with some random offset so we don't recycle all |
|
106 | 108 | # at once |
|
107 | worker._last_memory_check_time = _time_with_offset() | |
|
109 | worker._last_memory_check_time = _time_with_offset(_memory_usage_check_interval) | |
|
110 | ||
|
111 | if _memory_max_usage: | |
|
112 | server.log.info("[%-10s] WORKER spawned with max memory set at %s", worker.pid, | |
|
113 | _format_data_size(_memory_max_usage)) | |
|
114 | else: | |
|
115 | server.log.info("[%-10s] WORKER spawned", worker.pid) | |
|
108 | 116 | |
|
109 | 117 | |
|
110 | 118 | def pre_exec(server): |
@@ -173,32 +181,35 b' def _format_data_size(size, unit="B", pr' | |||
|
173 | 181 | |
|
174 | 182 | |
|
175 | 183 | def _check_memory_usage(worker): |
|
184 | memory_max_usage = worker._memory_max_usage | |
|
185 | if not memory_max_usage: | |
|
186 | return | |
|
176 | 187 | |
|
177 | if not MAX_MEMORY_USAGE: | |
|
178 | return | |
|
188 | memory_usage_check_interval = worker._memory_usage_check_interval | |
|
189 | memory_usage_recovery_threshold = memory_max_usage * worker._memory_usage_recovery_threshold | |
|
179 | 190 | |
|
180 | 191 | elapsed = time.time() - worker._last_memory_check_time |
|
181 | if elapsed > MEMORY_USAGE_CHECK_INTERVAL: | |
|
192 | if elapsed > memory_usage_check_interval: | |
|
182 | 193 | mem_usage = _get_process_rss() |
|
183 |
if mem_usage and mem_usage > |
|
|
194 | if mem_usage and mem_usage > memory_max_usage: | |
|
184 | 195 | worker.log.info( |
|
185 | 196 | "memory usage %s > %s, forcing gc", |
|
186 |
_format_data_size(mem_usage), _format_data_size( |
|
|
197 | _format_data_size(mem_usage), _format_data_size(memory_max_usage)) | |
|
187 | 198 | # Try to clean it up by forcing a full collection. |
|
188 | 199 | gc.collect() |
|
189 | 200 | mem_usage = _get_process_rss() |
|
190 | if mem_usage > MEMORY_USAGE_RECOVERY_THRESHOLD: | |
|
201 | if mem_usage > memory_usage_recovery_threshold: | |
|
191 | 202 | # Didn't clean up enough, we'll have to terminate. |
|
192 | 203 | worker.log.warning( |
|
193 | 204 | "memory usage %s > %s after gc, quitting", |
|
194 |
_format_data_size(mem_usage), _format_data_size( |
|
|
205 | _format_data_size(mem_usage), _format_data_size(memory_max_usage)) | |
|
195 | 206 | # This will cause worker to auto-restart itself |
|
196 | 207 | worker.alive = False |
|
197 | 208 | worker._last_memory_check_time = time.time() |
|
198 | 209 | |
|
199 | 210 | |
|
200 | 211 | def worker_int(worker): |
|
201 |
worker.log.info("[ |
|
|
212 | worker.log.info("[%-10s] worker received INT or QUIT signal", worker.pid) | |
|
202 | 213 | |
|
203 | 214 | # get traceback info, on worker crash |
|
204 | 215 | id2name = dict([(th.ident, th.name) for th in threading.enumerate()]) |
@@ -214,15 +225,15 b' def worker_int(worker):' | |||
|
214 | 225 | |
|
215 | 226 | |
|
216 | 227 | def worker_abort(worker): |
|
217 |
worker.log.info("[ |
|
|
228 | worker.log.info("[%-10s] worker received SIGABRT signal", worker.pid) | |
|
218 | 229 | |
|
219 | 230 | |
|
220 | 231 | def worker_exit(server, worker): |
|
221 |
worker.log.info("[ |
|
|
232 | worker.log.info("[%-10s] worker exit", worker.pid) | |
|
222 | 233 | |
|
223 | 234 | |
|
224 | 235 | def child_exit(server, worker): |
|
225 |
worker.log.info("[ |
|
|
236 | worker.log.info("[%-10s] worker child exit", worker.pid) | |
|
226 | 237 | |
|
227 | 238 | |
|
228 | 239 | def pre_request(worker, req): |
@@ -8,29 +8,92 b'' | |||
|
8 | 8 | host = 127.0.0.1 |
|
9 | 9 | port = 9900 |
|
10 | 10 | |
|
11 | ########################################################### | |
|
12 | ## WAITRESS WSGI SERVER - Recommended for Development #### | |
|
13 | ########################################################### | |
|
14 | ||
|
15 | #use = egg:waitress#main | |
|
16 | ## number of worker threads | |
|
17 | #threads = 5 | |
|
18 | ## MAX BODY SIZE 100GB | |
|
19 | #max_request_body_size = 107374182400 | |
|
20 | ## Use poll instead of select, fixes file descriptors limits problems. | |
|
21 | ## May not work on old windows systems. | |
|
22 | #asyncore_use_poll = true | |
|
23 | ||
|
11 | 24 | |
|
12 | 25 | ########################## |
|
13 | 26 | ## GUNICORN WSGI SERVER ## |
|
14 | 27 | ########################## |
|
15 | 28 | ## run with gunicorn --log-config vcsserver.ini --paste vcsserver.ini |
|
29 | ||
|
16 | 30 | use = egg:gunicorn#main |
|
17 |
## Sets the number of process workers. |
|
|
18 | ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers | |
|
31 | ## Sets the number of process workers. More workers means more concurrent connections | |
|
32 | ## RhodeCode can handle at the same time. Each additional worker also it increases | |
|
33 | ## memory usage as each has it's own set of caches. | |
|
34 | ## Recommended value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers, but no more | |
|
35 | ## than 8-10 unless for really big deployments .e.g 700-1000 users. | |
|
36 | ## `instance_id = *` must be set in the [app:main] section below (which is the default) | |
|
37 | ## when using more than 1 worker. | |
|
19 | 38 | workers = 2 |
|
20 | ## process name | |
|
39 | ||
|
40 | ## Gunicorn access log level | |
|
41 | loglevel = info | |
|
42 | ||
|
43 | ## process name visible in process list | |
|
21 | 44 | proc_name = rhodecode_vcsserver |
|
45 | ||
|
22 | 46 | ## type of worker class, currently `sync` is the only option allowed. |
|
23 | 47 | worker_class = sync |
|
48 | ||
|
24 | 49 | ## The maximum number of simultaneous clients. Valid only for Gevent |
|
25 |
|
|
|
50 | worker_connections = 10 | |
|
51 | ||
|
26 | 52 | ## max number of requests that worker will handle before being gracefully |
|
27 | 53 | ## restarted, could prevent memory leaks |
|
28 | 54 | max_requests = 1000 |
|
29 | 55 | max_requests_jitter = 30 |
|
56 | ||
|
30 | 57 | ## amount of time a worker can spend with handling a request before it |
|
31 | 58 | ## gets killed and restarted. Set to 6hrs |
|
32 | 59 | timeout = 21600 |
|
33 | 60 | |
|
61 | ## The maximum size of HTTP request line in bytes. | |
|
62 | ## 0 for unlimited | |
|
63 | limit_request_line = 0 | |
|
64 | ||
|
65 | ## Limit the number of HTTP headers fields in a request. | |
|
66 | ## By default this value is 100 and can't be larger than 32768. | |
|
67 | limit_request_fields = 32768 | |
|
68 | ||
|
69 | ## Limit the allowed size of an HTTP request header field. | |
|
70 | ## Value is a positive number or 0. | |
|
71 | ## Setting it to 0 will allow unlimited header field sizes. | |
|
72 | limit_request_field_size = 0 | |
|
73 | ||
|
74 | ## Timeout for graceful workers restart. | |
|
75 | ## After receiving a restart signal, workers have this much time to finish | |
|
76 | ## serving requests. Workers still alive after the timeout (starting from the | |
|
77 | ## receipt of the restart signal) are force killed. | |
|
78 | graceful_timeout = 3600 | |
|
79 | ||
|
80 | # The number of seconds to wait for requests on a Keep-Alive connection. | |
|
81 | # Generally set in the 1-5 seconds range. | |
|
82 | keepalive = 2 | |
|
83 | ||
|
84 | ## Maximum memory usage that each worker can use before it will receive a | |
|
85 | ## graceful restart signal, e.g 10MB = 10485760 (10 * 1024 * 1024) | |
|
86 | # 0 = memory monitoring is disabled | |
|
87 | memory_max_usage = 0 | |
|
88 | ||
|
89 | ## How often in seconds to check for memory usage for each gunicorn worker | |
|
90 | memory_usage_check_interval = 60 | |
|
91 | ||
|
92 | ## Threshold value for which we don't recycle worker if GarbageCollection | |
|
93 | ## frees up enough resources. Before each restart we try to run GC on worker | |
|
94 | ## in case we get enough free memory after that, restart will not happen. | |
|
95 | memory_usage_recovery_threshold = 0.8 | |
|
96 | ||
|
34 | 97 | |
|
35 | 98 | [app:main] |
|
36 | 99 | use = egg:rhodecode-vcsserver |
General Comments 0
You need to be logged in to leave comments.
Login now