##// END OF EJS Templates
configs: moved all gunicorn config to python file
super-admin -
r1143:7071fe53 default
parent child Browse files
Show More
@@ -1,275 +1,204 b''
1 #
1 #
2
2
3 ; #################################
3 ; #################################
4 ; RHODECODE VCSSERVER CONFIGURATION
4 ; RHODECODE VCSSERVER CONFIGURATION
5 ; #################################
5 ; #################################
6
6
7 [server:main]
7 [server:main]
8 ; COMMON HOST/IP CONFIG
8 ; COMMON HOST/IP CONFIG
9 host = 0.0.0.0
9 host = 0.0.0.0
10 port = 9900
10 port = 10010
11
11
12 ; ##################################################
12 ; ##################################################
13 ; WAITRESS WSGI SERVER - Recommended for Development
13 ; WAITRESS WSGI SERVER - Recommended for Development
14 ; ##################################################
14 ; ##################################################
15
15
16 ; use server type
16 ; use server type
17 use = egg:waitress#main
17 use = egg:waitress#main
18
18
19 ; number of worker threads
19 ; number of worker threads
20 threads = 5
20 threads = 5
21
21
22 ; MAX BODY SIZE 100GB
22 ; MAX BODY SIZE 100GB
23 max_request_body_size = 107374182400
23 max_request_body_size = 107374182400
24
24
25 ; Use poll instead of select, fixes file descriptors limits problems.
25 ; Use poll instead of select, fixes file descriptors limits problems.
26 ; May not work on old windows systems.
26 ; May not work on old windows systems.
27 asyncore_use_poll = true
27 asyncore_use_poll = true
28
28
29
29
30 ; ###########################
30 ; ###########################
31 ; GUNICORN APPLICATION SERVER
31 ; GUNICORN APPLICATION SERVER
32 ; ###########################
32 ; ###########################
33
33
34 ; run with gunicorn --paste rhodecode.ini
34 ; run with gunicorn --paste rhodecode.ini
35
35
36 ; Module to use, this setting shouldn't be changed
36 ; Module to use, this setting shouldn't be changed
37 #use = egg:gunicorn#main
37 #use = egg:gunicorn#main
38
38
39 ; Sets the number of process workers. More workers means more concurrent connections
40 ; RhodeCode can handle at the same time. Each additional worker also it increases
41 ; memory usage as each has it's own set of caches.
42 ; Recommended value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers, but no more
43 ; than 8-10 unless for really big deployments .e.g 700-1000 users.
44 ; `instance_id = *` must be set in the [app:main] section below (which is the default)
45 ; when using more than 1 worker.
46 #workers = 2
47
48 ; Gunicorn access log level
49 #loglevel = info
50
51 ; Process name visible in process list
52 #proc_name = rhodecode_vcsserver
53
54 ; Type of worker class, one of `sync`, `gevent`
55 ; currently `sync` is the only option allowed.
56 #worker_class = sync
57
58 ; The maximum number of simultaneous clients. Valid only for gevent
59 #worker_connections = 10
60
61 ; Max number of requests that worker will handle before being gracefully restarted.
62 ; Prevents memory leaks, jitter adds variability so not all workers are restarted at once.
63 #max_requests = 1000
64 #max_requests_jitter = 30
65
66 ; Amount of time a worker can spend with handling a request before it
67 ; gets killed and restarted. By default set to 21600 (6hrs)
68 ; Examples: 1800 (30min), 3600 (1hr), 7200 (2hr), 43200 (12h)
69 #timeout = 21600
70
71 ; The maximum size of HTTP request line in bytes.
72 ; 0 for unlimited
73 #limit_request_line = 0
74
75 ; Limit the number of HTTP headers fields in a request.
76 ; By default this value is 100 and can't be larger than 32768.
77 #limit_request_fields = 32768
78
79 ; Limit the allowed size of an HTTP request header field.
80 ; Value is a positive number or 0.
81 ; Setting it to 0 will allow unlimited header field sizes.
82 #limit_request_field_size = 0
83
84 ; Timeout for graceful workers restart.
85 ; After receiving a restart signal, workers have this much time to finish
86 ; serving requests. Workers still alive after the timeout (starting from the
87 ; receipt of the restart signal) are force killed.
88 ; Examples: 1800 (30min), 3600 (1hr), 7200 (2hr), 43200 (12h)
89 #graceful_timeout = 21600
90
91 # The number of seconds to wait for requests on a Keep-Alive connection.
92 # Generally set in the 1-5 seconds range.
93 #keepalive = 2
94
95 ; Maximum memory usage that each worker can use before it will receive a
96 ; graceful restart signal 0 = memory monitoring is disabled
97 ; Examples: 268435456 (256MB), 536870912 (512MB)
98 ; 1073741824 (1GB), 2147483648 (2GB), 4294967296 (4GB)
99 #memory_max_usage = 0
100
101 ; How often in seconds to check for memory usage for each gunicorn worker
102 #memory_usage_check_interval = 60
103
104 ; Threshold value for which we don't recycle worker if GarbageCollection
105 ; frees up enough resources. Before each restart we try to run GC on worker
106 ; in case we get enough free memory after that, restart will not happen.
107 #memory_usage_recovery_threshold = 0.8
108
109
110 [app:main]
39 [app:main]
111 ; The %(here)s variable will be replaced with the absolute path of parent directory
40 ; The %(here)s variable will be replaced with the absolute path of parent directory
112 ; of this file
41 ; of this file
113 ; Each option in the app:main can be override by an environmental variable
42 ; Each option in the app:main can be override by an environmental variable
114 ;
43 ;
115 ;To override an option:
44 ;To override an option:
116 ;
45 ;
117 ;RC_<KeyName>
46 ;RC_<KeyName>
118 ;Everything should be uppercase, . and - should be replaced by _.
47 ;Everything should be uppercase, . and - should be replaced by _.
119 ;For example, if you have these configuration settings:
48 ;For example, if you have these configuration settings:
120 ;rc_cache.repo_object.backend = foo
49 ;rc_cache.repo_object.backend = foo
121 ;can be overridden by
50 ;can be overridden by
122 ;export RC_CACHE_REPO_OBJECT_BACKEND=foo
51 ;export RC_CACHE_REPO_OBJECT_BACKEND=foo
123
52
124 use = egg:rhodecode-vcsserver
53 use = egg:rhodecode-vcsserver
125
54
126
55
127 ; #############
56 ; #############
128 ; DEBUG OPTIONS
57 ; DEBUG OPTIONS
129 ; #############
58 ; #############
130
59
131 # During development the we want to have the debug toolbar enabled
60 # During development the we want to have the debug toolbar enabled
132 pyramid.includes =
61 pyramid.includes =
133 pyramid_debugtoolbar
62 pyramid_debugtoolbar
134
63
135 debugtoolbar.hosts = 0.0.0.0/0
64 debugtoolbar.hosts = 0.0.0.0/0
136 debugtoolbar.exclude_prefixes =
65 debugtoolbar.exclude_prefixes =
137 /css
66 /css
138 /fonts
67 /fonts
139 /images
68 /images
140 /js
69 /js
141
70
142 ; #################
71 ; #################
143 ; END DEBUG OPTIONS
72 ; END DEBUG OPTIONS
144 ; #################
73 ; #################
145
74
146 ; Pyramid default locales, we need this to be set
75 ; Pyramid default locales, we need this to be set
147 #pyramid.default_locale_name = en
76 #pyramid.default_locale_name = en
148
77
149 ; default locale used by VCS systems
78 ; default locale used by VCS systems
150 #locale = en_US.UTF-8
79 #locale = en_US.UTF-8
151
80
152 ; path to binaries for vcsserver, it should be set by the installer
81 ; path to binaries for vcsserver, it should be set by the installer
153 ; at installation time, e.g /home/user/.rccontrol/vcsserver-1/profile/bin
82 ; at installation time, e.g /home/user/.rccontrol/vcsserver-1/profile/bin
154 ; it can also be a path to nix-build output in case of development
83 ; it can also be a path to nix-build output in case of development
155 core.binary_dir = ""
84 core.binary_dir = ""
156
85
157 ; Custom exception store path, defaults to TMPDIR
86 ; Custom exception store path, defaults to TMPDIR
158 ; This is used to store exception from RhodeCode in shared directory
87 ; This is used to store exception from RhodeCode in shared directory
159 #exception_tracker.store_path =
88 #exception_tracker.store_path =
160
89
161 ; #############
90 ; #############
162 ; DOGPILE CACHE
91 ; DOGPILE CACHE
163 ; #############
92 ; #############
164
93
165 ; Default cache dir for caches. Putting this into a ramdisk can boost performance.
94 ; Default cache dir for caches. Putting this into a ramdisk can boost performance.
166 ; eg. /tmpfs/data_ramdisk, however this directory might require large amount of space
95 ; eg. /tmpfs/data_ramdisk, however this directory might require large amount of space
167 #cache_dir = %(here)s/data
96 #cache_dir = %(here)s/data
168
97
169 ; ***************************************
98 ; ***************************************
170 ; `repo_object` cache, default file based
99 ; `repo_object` cache, default file based
171 ; ***************************************
100 ; ***************************************
172
101
173 ; `repo_object` cache settings for vcs methods for repositories
102 ; `repo_object` cache settings for vcs methods for repositories
174 #rc_cache.repo_object.backend = dogpile.cache.rc.file_namespace
103 #rc_cache.repo_object.backend = dogpile.cache.rc.file_namespace
175
104
176 ; cache auto-expires after N seconds
105 ; cache auto-expires after N seconds
177 ; Examples: 86400 (1Day), 604800 (7Days), 1209600 (14Days), 2592000 (30days), 7776000 (90Days)
106 ; Examples: 86400 (1Day), 604800 (7Days), 1209600 (14Days), 2592000 (30days), 7776000 (90Days)
178 #rc_cache.repo_object.expiration_time = 2592000
107 #rc_cache.repo_object.expiration_time = 2592000
179
108
180 ; file cache store path. Defaults to `cache_dir =` value or tempdir if both values are not set
109 ; file cache store path. Defaults to `cache_dir =` value or tempdir if both values are not set
181 #rc_cache.repo_object.arguments.filename = /tmp/vcsserver_cache_repo_object.db
110 #rc_cache.repo_object.arguments.filename = /tmp/vcsserver_cache_repo_object.db
182
111
183 ; ***********************************************************
112 ; ***********************************************************
184 ; `repo_object` cache with redis backend
113 ; `repo_object` cache with redis backend
185 ; recommended for larger instance, and for better performance
114 ; recommended for larger instance, and for better performance
186 ; ***********************************************************
115 ; ***********************************************************
187
116
188 ; `repo_object` cache settings for vcs methods for repositories
117 ; `repo_object` cache settings for vcs methods for repositories
189 #rc_cache.repo_object.backend = dogpile.cache.rc.redis_msgpack
118 #rc_cache.repo_object.backend = dogpile.cache.rc.redis_msgpack
190
119
191 ; cache auto-expires after N seconds
120 ; cache auto-expires after N seconds
192 ; Examples: 86400 (1Day), 604800 (7Days), 1209600 (14Days), 2592000 (30days), 7776000 (90Days)
121 ; Examples: 86400 (1Day), 604800 (7Days), 1209600 (14Days), 2592000 (30days), 7776000 (90Days)
193 #rc_cache.repo_object.expiration_time = 2592000
122 #rc_cache.repo_object.expiration_time = 2592000
194
123
195 ; redis_expiration_time needs to be greater then expiration_time
124 ; redis_expiration_time needs to be greater then expiration_time
196 #rc_cache.repo_object.arguments.redis_expiration_time = 3592000
125 #rc_cache.repo_object.arguments.redis_expiration_time = 3592000
197
126
198 #rc_cache.repo_object.arguments.host = localhost
127 #rc_cache.repo_object.arguments.host = localhost
199 #rc_cache.repo_object.arguments.port = 6379
128 #rc_cache.repo_object.arguments.port = 6379
200 #rc_cache.repo_object.arguments.db = 5
129 #rc_cache.repo_object.arguments.db = 5
201 #rc_cache.repo_object.arguments.socket_timeout = 30
130 #rc_cache.repo_object.arguments.socket_timeout = 30
202 ; more Redis options: https://dogpilecache.sqlalchemy.org/en/latest/api.html#redis-backends
131 ; more Redis options: https://dogpilecache.sqlalchemy.org/en/latest/api.html#redis-backends
203 #rc_cache.repo_object.arguments.distributed_lock = true
132 #rc_cache.repo_object.arguments.distributed_lock = true
204
133
205 ; auto-renew lock to prevent stale locks, slower but safer. Use only if problems happen
134 ; auto-renew lock to prevent stale locks, slower but safer. Use only if problems happen
206 #rc_cache.repo_object.arguments.lock_auto_renewal = true
135 #rc_cache.repo_object.arguments.lock_auto_renewal = true
207
136
208 ; Statsd client config, this is used to send metrics to statsd
137 ; Statsd client config, this is used to send metrics to statsd
209 ; We recommend setting statsd_exported and scrape them using Promethues
138 ; We recommend setting statsd_exported and scrape them using Promethues
210 #statsd.enabled = false
139 #statsd.enabled = false
211 #statsd.statsd_host = 0.0.0.0
140 #statsd.statsd_host = 0.0.0.0
212 #statsd.statsd_port = 8125
141 #statsd.statsd_port = 8125
213 #statsd.statsd_prefix =
142 #statsd.statsd_prefix =
214 #statsd.statsd_ipv6 = false
143 #statsd.statsd_ipv6 = false
215
144
216 ; configure logging automatically at server startup set to false
145 ; configure logging automatically at server startup set to false
217 ; to use the below custom logging config.
146 ; to use the below custom logging config.
218 ; RC_LOGGING_FORMATTER
147 ; RC_LOGGING_FORMATTER
219 ; RC_LOGGING_LEVEL
148 ; RC_LOGGING_LEVEL
220 ; env variables can control the settings for logging in case of autoconfigure
149 ; env variables can control the settings for logging in case of autoconfigure
221
150
222 #logging.autoconfigure = true
151 #logging.autoconfigure = true
223
152
224 ; specify your own custom logging config file to configure logging
153 ; specify your own custom logging config file to configure logging
225 #logging.logging_conf_file = /path/to/custom_logging.ini
154 #logging.logging_conf_file = /path/to/custom_logging.ini
226
155
227 ; #####################
156 ; #####################
228 ; LOGGING CONFIGURATION
157 ; LOGGING CONFIGURATION
229 ; #####################
158 ; #####################
230
159
231 [loggers]
160 [loggers]
232 keys = root, vcsserver
161 keys = root, vcsserver
233
162
234 [handlers]
163 [handlers]
235 keys = console
164 keys = console
236
165
237 [formatters]
166 [formatters]
238 keys = generic, json
167 keys = generic, json
239
168
240 ; #######
169 ; #######
241 ; LOGGERS
170 ; LOGGERS
242 ; #######
171 ; #######
243 [logger_root]
172 [logger_root]
244 level = NOTSET
173 level = NOTSET
245 handlers = console
174 handlers = console
246
175
247 [logger_vcsserver]
176 [logger_vcsserver]
248 level = DEBUG
177 level = DEBUG
249 handlers =
178 handlers =
250 qualname = vcsserver
179 qualname = vcsserver
251 propagate = 1
180 propagate = 1
252
181
253 ; ########
182 ; ########
254 ; HANDLERS
183 ; HANDLERS
255 ; ########
184 ; ########
256
185
257 [handler_console]
186 [handler_console]
258 class = StreamHandler
187 class = StreamHandler
259 args = (sys.stderr, )
188 args = (sys.stderr, )
260 level = DEBUG
189 level = DEBUG
261 ; To enable JSON formatted logs replace 'generic' with 'json'
190 ; To enable JSON formatted logs replace 'generic' with 'json'
262 ; This allows sending properly formatted logs to grafana loki or elasticsearch
191 ; This allows sending properly formatted logs to grafana loki or elasticsearch
263 formatter = generic
192 formatter = generic
264
193
265 ; ##########
194 ; ##########
266 ; FORMATTERS
195 ; FORMATTERS
267 ; ##########
196 ; ##########
268
197
269 [formatter_generic]
198 [formatter_generic]
270 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
199 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
271 datefmt = %Y-%m-%d %H:%M:%S
200 datefmt = %Y-%m-%d %H:%M:%S
272
201
273 [formatter_json]
202 [formatter_json]
274 format = %(timestamp)s %(levelname)s %(name)s %(message)s %(req_id)s
203 format = %(timestamp)s %(levelname)s %(name)s %(message)s %(req_id)s
275 class = vcsserver.lib._vendor.jsonlogger.JsonFormatter
204 class = vcsserver.lib._vendor.jsonlogger.JsonFormatter
@@ -1,393 +1,506 b''
1 """
1 """
2 Gunicorn config extension and hooks. This config file adds some extra settings and memory management.
2 Gunicorn config extension and hooks. This config file adds some extra settings and memory management.
3 Gunicorn configuration should be managed by .ini files entries of RhodeCode or VCSServer
3 Gunicorn configuration should be managed by .ini files entries of RhodeCode or VCSServer
4 """
4 """
5
5
6 import gc
6 import gc
7 import os
7 import os
8 import sys
8 import sys
9 import math
9 import math
10 import time
10 import time
11 import threading
11 import threading
12 import traceback
12 import traceback
13 import random
13 import random
14 import socket
14 import socket
15 import dataclasses
15 from gunicorn.glogging import Logger
16 from gunicorn.glogging import Logger
16
17
17
18
18 def get_workers():
19 def get_workers():
19 import multiprocessing
20 import multiprocessing
20 return multiprocessing.cpu_count() * 2 + 1
21 return multiprocessing.cpu_count() * 2 + 1
21
22
22 # GLOBAL
23
24 bind = "127.0.0.1:10010"
25
26
27 # Error logging output for gunicorn (-) is stdout
23 errorlog = '-'
28 errorlog = '-'
29
30 # Access logging output for gunicorn (-) is stdout
24 accesslog = '-'
31 accesslog = '-'
25
32
26
33
27 # SERVER MECHANICS
34 # SERVER MECHANICS
28 # None == system temp dir
35 # None == system temp dir
29 # worker_tmp_dir is recommended to be set to some tmpfs
36 # worker_tmp_dir is recommended to be set to some tmpfs
30 worker_tmp_dir = None
37 worker_tmp_dir = None
31 tmp_upload_dir = None
38 tmp_upload_dir = None
32
39
40 # use re-use port logic
33 #reuse_port = True
41 #reuse_port = True
34
42
35 # Custom log format
43 # Custom log format
36 #access_log_format = (
44 #access_log_format = (
37 # '%(t)s %(p)s INFO [GNCRN] %(h)-15s rqt:%(L)s %(s)s %(b)-6s "%(m)s:%(U)s %(q)s" usr:%(u)s "%(f)s" "%(a)s"')
45 # '%(t)s %(p)s INFO [GNCRN] %(h)-15s rqt:%(L)s %(s)s %(b)-6s "%(m)s:%(U)s %(q)s" usr:%(u)s "%(f)s" "%(a)s"')
38
46
39 # loki format for easier parsing in grafana
47 # loki format for easier parsing in grafana
40 access_log_format = (
48 access_log_format = (
41 'time="%(t)s" pid=%(p)s level="INFO" type="[GNCRN]" ip="%(h)-15s" rqt="%(L)s" response_code="%(s)s" response_bytes="%(b)-6s" uri="%(m)s:%(U)s %(q)s" user=":%(u)s" user_agent="%(a)s"')
49 'time="%(t)s" pid=%(p)s level="INFO" type="[GNCRN]" ip="%(h)-15s" rqt="%(L)s" response_code="%(s)s" response_bytes="%(b)-6s" uri="%(m)s:%(U)s %(q)s" user=":%(u)s" user_agent="%(a)s"')
42
50
43 # self adjust workers based on CPU count
51
52 # Sets the number of process workers. More workers means more concurrent connections
53 # RhodeCode can handle at the same time. Each additional worker also it increases
54 # memory usage as each has it's own set of caches.
55 # Recommended value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers, but no more
56 # than 8-10 unless for huge deployments .e.g 700-1000 users.
57 # `instance_id = *` must be set in the [app:main] section below (which is the default)
58 # when using more than 1 worker.
59 workers = 6
60
61 # self adjust workers based on CPU count, to use maximum of CPU and not overquota the resources
44 # workers = get_workers()
62 # workers = get_workers()
45
63
64 # Gunicorn access log level
65 loglevel = 'info'
66
67 # Process name visible in process list
68 proc_name = 'rhodecode_vcsserver'
69
70 # Type of worker class, one of `sync`, `gevent`
71 # currently `sync` is the only option allowed.
72 worker_class = 'sync'
73
74 # The maximum number of simultaneous clients. Valid only for gevent
75 worker_connections = 10
76
77 # Max number of requests that worker will handle before being gracefully restarted.
78 # Prevents memory leaks, jitter adds variability so not all workers are restarted at once.
79 max_requests = 2000
80 max_requests_jitter = 30
81
82 # The maximum number of pending connections.
83 # Exceeding this number results in the client getting an error when attempting to connect.
84 backlog = 64
85
86 # Amount of time a worker can spend with handling a request before it
87 # gets killed and restarted. By default set to 21600 (6hrs)
88 # Examples: 1800 (30min), 3600 (1hr), 7200 (2hr), 43200 (12h)
89 timeout = 21600
90
91 # The maximum size of HTTP request line in bytes.
92 # 0 for unlimited
93 limit_request_line = 0
94
95 # Limit the number of HTTP headers fields in a request.
96 # By default this value is 100 and can't be larger than 32768.
97 limit_request_fields = 32768
98
99 # Limit the allowed size of an HTTP request header field.
100 # Value is a positive number or 0.
101 # Setting it to 0 will allow unlimited header field sizes.
102 limit_request_field_size = 0
103
104 # Timeout for graceful workers restart.
105 # After receiving a restart signal, workers have this much time to finish
106 # serving requests. Workers still alive after the timeout (starting from the
107 # receipt of the restart signal) are force killed.
108 # Examples: 1800 (30min), 3600 (1hr), 7200 (2hr), 43200 (12h)
109 graceful_timeout = 21600
110
111 # The number of seconds to wait for requests on a Keep-Alive connection.
112 # Generally set in the 1-5 seconds range.
113 keepalive = 2
114
115 # Maximum memory usage that each worker can use before it will receive a
116 # graceful restart signal 0 = memory monitoring is disabled
117 # Examples: 268435456 (256MB), 536870912 (512MB)
118 # 1073741824 (1GB), 2147483648 (2GB), 4294967296 (4GB)
119 memory_max_usage = 0
120
121 # How often in seconds to check for memory usage for each gunicorn worker
122 memory_usage_check_interval = 60
123
124 # Threshold value for which we don't recycle worker if GarbageCollection
125 # frees up enough resources. Before each restart we try to run GC on worker
126 # in case we get enough free memory after that, restart will not happen.
127 memory_usage_recovery_threshold = 0.8
128
129
130 @dataclasses.dataclass
131 class MemoryCheckConfig:
132 max_usage: int
133 check_interval: int
134 recovery_threshold: float
135
46
136
47 def _get_process_rss(pid=None):
137 def _get_process_rss(pid=None):
48 try:
138 try:
49 import psutil
139 import psutil
50 if pid:
140 if pid:
51 proc = psutil.Process(pid)
141 proc = psutil.Process(pid)
52 else:
142 else:
53 proc = psutil.Process()
143 proc = psutil.Process()
54 return proc.memory_info().rss
144 return proc.memory_info().rss
55 except Exception:
145 except Exception:
56 return None
146 return None
57
147
58
148
59 def _get_config(ini_path):
149 def _get_config(ini_path):
60 import configparser
150 import configparser
61
151
62 try:
152 try:
63 config = configparser.RawConfigParser()
153 config = configparser.RawConfigParser()
64 config.read(ini_path)
154 config.read(ini_path)
65 return config
155 return config
66 except Exception:
156 except Exception:
67 return None
157 return None
68
158
69
159
70 def _time_with_offset(memory_usage_check_interval):
160 def get_memory_usage_params(config=None):
71 return time.time() - random.randint(0, memory_usage_check_interval/2.0)
161 # memory spec defaults
162 _memory_max_usage = memory_max_usage
163 _memory_usage_check_interval = memory_usage_check_interval
164 _memory_usage_recovery_threshold = memory_usage_recovery_threshold
165
166 if config:
167 ini_path = os.path.abspath(config)
168 conf = _get_config(ini_path)
169
170 section = 'server:main'
171 if conf and conf.has_section(section):
172
173 if conf.has_option(section, 'memory_max_usage'):
174 _memory_max_usage = conf.getint(section, 'memory_max_usage')
175
176 if conf.has_option(section, 'memory_usage_check_interval'):
177 _memory_usage_check_interval = conf.getint(section, 'memory_usage_check_interval')
178
179 if conf.has_option(section, 'memory_usage_recovery_threshold'):
180 _memory_usage_recovery_threshold = conf.getfloat(section, 'memory_usage_recovery_threshold')
181
182 _memory_max_usage = int(os.environ.get('RC_GUNICORN_MEMORY_MAX_USAGE', '')
183 or _memory_max_usage)
184 _memory_usage_check_interval = int(os.environ.get('RC_GUNICORN_MEMORY_USAGE_CHECK_INTERVAL', '')
185 or _memory_usage_check_interval)
186 _memory_usage_recovery_threshold = float(os.environ.get('RC_GUNICORN_MEMORY_USAGE_RECOVERY_THRESHOLD', '')
187 or _memory_usage_recovery_threshold)
188
189 return MemoryCheckConfig(_memory_max_usage, _memory_usage_check_interval, _memory_usage_recovery_threshold)
190
191
192 def _time_with_offset(check_interval):
193 return time.time() - random.randint(0, check_interval/2.0)
72
194
73
195
74 def pre_fork(server, worker):
196 def pre_fork(server, worker):
75 pass
197 pass
76
198
77
199
78 def post_fork(server, worker):
200 def post_fork(server, worker):
79
201
80 # memory spec defaults
202 memory_conf = get_memory_usage_params()
81 _memory_max_usage = 0
203 _memory_max_usage = memory_conf.max_usage
82 _memory_usage_check_interval = 60
204 _memory_usage_check_interval = memory_conf.check_interval
83 _memory_usage_recovery_threshold = 0.8
205 _memory_usage_recovery_threshold = memory_conf.recovery_threshold
84
85 ini_path = os.path.abspath(server.cfg.paste)
86 conf = _get_config(ini_path)
87
88 section = 'server:main'
89 if conf and conf.has_section(section):
90
91 if conf.has_option(section, 'memory_max_usage'):
92 _memory_max_usage = conf.getint(section, 'memory_max_usage')
93
94 if conf.has_option(section, 'memory_usage_check_interval'):
95 _memory_usage_check_interval = conf.getint(section, 'memory_usage_check_interval')
96
97 if conf.has_option(section, 'memory_usage_recovery_threshold'):
98 _memory_usage_recovery_threshold = conf.getfloat(section, 'memory_usage_recovery_threshold')
99
206
100 worker._memory_max_usage = int(os.environ.get('RC_GUNICORN_MEMORY_MAX_USAGE', '')
207 worker._memory_max_usage = int(os.environ.get('RC_GUNICORN_MEMORY_MAX_USAGE', '')
101 or _memory_max_usage)
208 or _memory_max_usage)
102 worker._memory_usage_check_interval = int(os.environ.get('RC_GUNICORN_MEMORY_USAGE_CHECK_INTERVAL', '')
209 worker._memory_usage_check_interval = int(os.environ.get('RC_GUNICORN_MEMORY_USAGE_CHECK_INTERVAL', '')
103 or _memory_usage_check_interval)
210 or _memory_usage_check_interval)
104 worker._memory_usage_recovery_threshold = float(os.environ.get('RC_GUNICORN_MEMORY_USAGE_RECOVERY_THRESHOLD', '')
211 worker._memory_usage_recovery_threshold = float(os.environ.get('RC_GUNICORN_MEMORY_USAGE_RECOVERY_THRESHOLD', '')
105 or _memory_usage_recovery_threshold)
212 or _memory_usage_recovery_threshold)
106
213
107 # register memory last check time, with some random offset so we don't recycle all
214 # register memory last check time, with some random offset so we don't recycle all
108 # at once
215 # at once
109 worker._last_memory_check_time = _time_with_offset(_memory_usage_check_interval)
216 worker._last_memory_check_time = _time_with_offset(_memory_usage_check_interval)
110
217
111 if _memory_max_usage:
218 if _memory_max_usage:
112 server.log.info("[%-10s] WORKER spawned with max memory set at %s", worker.pid,
219 server.log.info("pid=[%-10s] WORKER spawned with max memory set at %s", worker.pid,
113 _format_data_size(_memory_max_usage))
220 _format_data_size(_memory_max_usage))
114 else:
221 else:
115 server.log.info("[%-10s] WORKER spawned", worker.pid)
222 server.log.info("pid=[%-10s] WORKER spawned", worker.pid)
116
223
117
224
118 def pre_exec(server):
225 def pre_exec(server):
119 server.log.info("Forked child, re-executing.")
226 server.log.info("Forked child, re-executing.")
120
227
121
228
122 def on_starting(server):
229 def on_starting(server):
123 server_lbl = '{} {}'.format(server.proc_name, server.address)
230 server_lbl = '{} {}'.format(server.proc_name, server.address)
124 server.log.info("Server %s is starting.", server_lbl)
231 server.log.info("Server %s is starting.", server_lbl)
125
232
126
233
127 def when_ready(server):
234 def when_ready(server):
128 server.log.info("Server %s is ready. Spawning workers", server)
235 server.log.info("Server %s is ready. Spawning workers", server)
129
236
130
237
131 def on_reload(server):
238 def on_reload(server):
132 pass
239 pass
133
240
134
241
135 def _format_data_size(size, unit="B", precision=1, binary=True):
242 def _format_data_size(size, unit="B", precision=1, binary=True):
136 """Format a number using SI units (kilo, mega, etc.).
243 """Format a number using SI units (kilo, mega, etc.).
137
244
138 ``size``: The number as a float or int.
245 ``size``: The number as a float or int.
139
246
140 ``unit``: The unit name in plural form. Examples: "bytes", "B".
247 ``unit``: The unit name in plural form. Examples: "bytes", "B".
141
248
142 ``precision``: How many digits to the right of the decimal point. Default
249 ``precision``: How many digits to the right of the decimal point. Default
143 is 1. 0 suppresses the decimal point.
250 is 1. 0 suppresses the decimal point.
144
251
145 ``binary``: If false, use base-10 decimal prefixes (kilo = K = 1000).
252 ``binary``: If false, use base-10 decimal prefixes (kilo = K = 1000).
146 If true, use base-2 binary prefixes (kibi = Ki = 1024).
253 If true, use base-2 binary prefixes (kibi = Ki = 1024).
147
254
148 ``full_name``: If false (default), use the prefix abbreviation ("k" or
255 ``full_name``: If false (default), use the prefix abbreviation ("k" or
149 "Ki"). If true, use the full prefix ("kilo" or "kibi"). If false,
256 "Ki"). If true, use the full prefix ("kilo" or "kibi"). If false,
150 use abbreviation ("k" or "Ki").
257 use abbreviation ("k" or "Ki").
151
258
152 """
259 """
153
260
154 if not binary:
261 if not binary:
155 base = 1000
262 base = 1000
156 multiples = ('', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
263 multiples = ('', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
157 else:
264 else:
158 base = 1024
265 base = 1024
159 multiples = ('', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi')
266 multiples = ('', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi')
160
267
161 sign = ""
268 sign = ""
162 if size > 0:
269 if size > 0:
163 m = int(math.log(size, base))
270 m = int(math.log(size, base))
164 elif size < 0:
271 elif size < 0:
165 sign = "-"
272 sign = "-"
166 size = -size
273 size = -size
167 m = int(math.log(size, base))
274 m = int(math.log(size, base))
168 else:
275 else:
169 m = 0
276 m = 0
170 if m > 8:
277 if m > 8:
171 m = 8
278 m = 8
172
279
173 if m == 0:
280 if m == 0:
174 precision = '%.0f'
281 precision = '%.0f'
175 else:
282 else:
176 precision = '%%.%df' % precision
283 precision = '%%.%df' % precision
177
284
178 size = precision % (size / math.pow(base, m))
285 size = precision % (size / math.pow(base, m))
179
286
180 return '%s%s %s%s' % (sign, size.strip(), multiples[m], unit)
287 return '%s%s %s%s' % (sign, size.strip(), multiples[m], unit)
181
288
182
289
183 def _check_memory_usage(worker):
290 def _check_memory_usage(worker):
184 memory_max_usage = worker._memory_max_usage
291 _memory_max_usage = worker._memory_max_usage
185 if not memory_max_usage:
292 if not _memory_max_usage:
186 return
293 return
187
294
188 memory_usage_check_interval = worker._memory_usage_check_interval
295 _memory_usage_check_interval = worker._memory_usage_check_interval
189 memory_usage_recovery_threshold = memory_max_usage * worker._memory_usage_recovery_threshold
296 _memory_usage_recovery_threshold = memory_max_usage * worker._memory_usage_recovery_threshold
190
297
191 elapsed = time.time() - worker._last_memory_check_time
298 elapsed = time.time() - worker._last_memory_check_time
192 if elapsed > memory_usage_check_interval:
299 if elapsed > _memory_usage_check_interval:
193 mem_usage = _get_process_rss()
300 mem_usage = _get_process_rss()
194 if mem_usage and mem_usage > memory_max_usage:
301 if mem_usage and mem_usage > _memory_max_usage:
195 worker.log.info(
302 worker.log.info(
196 "memory usage %s > %s, forcing gc",
303 "memory usage %s > %s, forcing gc",
197 _format_data_size(mem_usage), _format_data_size(memory_max_usage))
304 _format_data_size(mem_usage), _format_data_size(_memory_max_usage))
198 # Try to clean it up by forcing a full collection.
305 # Try to clean it up by forcing a full collection.
199 gc.collect()
306 gc.collect()
200 mem_usage = _get_process_rss()
307 mem_usage = _get_process_rss()
201 if mem_usage > memory_usage_recovery_threshold:
308 if mem_usage > _memory_usage_recovery_threshold:
202 # Didn't clean up enough, we'll have to terminate.
309 # Didn't clean up enough, we'll have to terminate.
203 worker.log.warning(
310 worker.log.warning(
204 "memory usage %s > %s after gc, quitting",
311 "memory usage %s > %s after gc, quitting",
205 _format_data_size(mem_usage), _format_data_size(memory_max_usage))
312 _format_data_size(mem_usage), _format_data_size(_memory_max_usage))
206 # This will cause worker to auto-restart itself
313 # This will cause worker to auto-restart itself
207 worker.alive = False
314 worker.alive = False
208 worker._last_memory_check_time = time.time()
315 worker._last_memory_check_time = time.time()
209
316
210
317
211 def worker_int(worker):
318 def worker_int(worker):
212 worker.log.info("[%-10s] worker received INT or QUIT signal", worker.pid)
319 worker.log.info("pid=[%-10s] worker received INT or QUIT signal", worker.pid)
213
320
214 # get traceback info, on worker crash
321 # get traceback info, on worker crash
215 id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
322 def get_thread_id(t_id):
323 id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
324 return id2name.get(t_id, "unknown_thread_id")
325
216 code = []
326 code = []
217 for thread_id, stack in sys._current_frames().items():
327 for thread_id, stack in sys._current_frames().items(): # noqa
218 code.append(
328 code.append(
219 "\n# Thread: %s(%d)" % (id2name.get(thread_id, ""), thread_id))
329 "\n# Thread: %s(%d)" % (get_thread_id(thread_id), thread_id))
220 for fname, lineno, name, line in traceback.extract_stack(stack):
330 for fname, lineno, name, line in traceback.extract_stack(stack):
221 code.append('File: "%s", line %d, in %s' % (fname, lineno, name))
331 code.append('File: "%s", line %d, in %s' % (fname, lineno, name))
222 if line:
332 if line:
223 code.append(" %s" % (line.strip()))
333 code.append(" %s" % (line.strip()))
224 worker.log.debug("\n".join(code))
334 worker.log.debug("\n".join(code))
225
335
226
336
227 def worker_abort(worker):
337 def worker_abort(worker):
228 worker.log.info("[%-10s] worker received SIGABRT signal", worker.pid)
338 worker.log.info("pid=[%-10s] worker received SIGABRT signal", worker.pid)
229
339
230
340
231 def worker_exit(server, worker):
341 def worker_exit(server, worker):
232 worker.log.info("[%-10s] worker exit", worker.pid)
342 worker.log.info("pid=[%-10s] worker exit", worker.pid)
233
343
234
344
235 def child_exit(server, worker):
345 def child_exit(server, worker):
236 worker.log.info("[%-10s] worker child exit", worker.pid)
346 worker.log.info("pid=[%-10s] worker child exit", worker.pid)
237
347
238
348
239 def pre_request(worker, req):
349 def pre_request(worker, req):
240 worker.start_time = time.time()
350 worker.start_time = time.time()
241 worker.log.debug(
351 worker.log.debug(
242 "GNCRN PRE WORKER [cnt:%s]: %s %s", worker.nr, req.method, req.path)
352 "GNCRN PRE WORKER [cnt:%s]: %s %s", worker.nr, req.method, req.path)
243
353
244
354
245 def post_request(worker, req, environ, resp):
355 def post_request(worker, req, environ, resp):
246 total_time = time.time() - worker.start_time
356 total_time = time.time() - worker.start_time
247 # Gunicorn sometimes has problems with reading the status_code
357 # Gunicorn sometimes has problems with reading the status_code
248 status_code = getattr(resp, 'status_code', '')
358 status_code = getattr(resp, 'status_code', '')
249 worker.log.debug(
359 worker.log.debug(
250 "GNCRN POST WORKER [cnt:%s]: %s %s resp: %s, Load Time: %.4fs",
360 "GNCRN POST WORKER [cnt:%s]: %s %s resp: %s, Load Time: %.4fs",
251 worker.nr, req.method, req.path, status_code, total_time)
361 worker.nr, req.method, req.path, status_code, total_time)
252 _check_memory_usage(worker)
362 _check_memory_usage(worker)
253
363
254
364
255 def _filter_proxy(ip):
365 def _filter_proxy(ip):
256 """
366 """
257 Passed in IP addresses in HEADERS can be in a special format of multiple
367 Passed in IP addresses in HEADERS can be in a special format of multiple
258 ips. Those comma separated IPs are passed from various proxies in the
368 ips. Those comma separated IPs are passed from various proxies in the
259 chain of request processing. The left-most being the original client.
369 chain of request processing. The left-most being the original client.
260 We only care about the first IP which came from the org. client.
370 We only care about the first IP which came from the org. client.
261
371
262 :param ip: ip string from headers
372 :param ip: ip string from headers
263 """
373 """
264 if ',' in ip:
374 if ',' in ip:
265 _ips = ip.split(',')
375 _ips = ip.split(',')
266 _first_ip = _ips[0].strip()
376 _first_ip = _ips[0].strip()
267 return _first_ip
377 return _first_ip
268 return ip
378 return ip
269
379
270
380
271 def _filter_port(ip):
381 def _filter_port(ip):
272 """
382 """
273 Removes a port from ip, there are 4 main cases to handle here.
383 Removes a port from ip, there are 4 main cases to handle here.
274 - ipv4 eg. 127.0.0.1
384 - ipv4 eg. 127.0.0.1
275 - ipv6 eg. ::1
385 - ipv6 eg. ::1
276 - ipv4+port eg. 127.0.0.1:8080
386 - ipv4+port eg. 127.0.0.1:8080
277 - ipv6+port eg. [::1]:8080
387 - ipv6+port eg. [::1]:8080
278
388
279 :param ip:
389 :param ip:
280 """
390 """
281 def is_ipv6(ip_addr):
391 def is_ipv6(ip_addr):
282 if hasattr(socket, 'inet_pton'):
392 if hasattr(socket, 'inet_pton'):
283 try:
393 try:
284 socket.inet_pton(socket.AF_INET6, ip_addr)
394 socket.inet_pton(socket.AF_INET6, ip_addr)
285 except socket.error:
395 except socket.error:
286 return False
396 return False
287 else:
397 else:
288 return False
398 return False
289 return True
399 return True
290
400
291 if ':' not in ip: # must be ipv4 pure ip
401 if ':' not in ip: # must be ipv4 pure ip
292 return ip
402 return ip
293
403
294 if '[' in ip and ']' in ip: # ipv6 with port
404 if '[' in ip and ']' in ip: # ipv6 with port
295 return ip.split(']')[0][1:].lower()
405 return ip.split(']')[0][1:].lower()
296
406
297 # must be ipv6 or ipv4 with port
407 # must be ipv6 or ipv4 with port
298 if is_ipv6(ip):
408 if is_ipv6(ip):
299 return ip
409 return ip
300 else:
410 else:
301 ip, _port = ip.split(':')[:2] # means ipv4+port
411 ip, _port = ip.split(':')[:2] # means ipv4+port
302 return ip
412 return ip
303
413
304
414
305 def get_ip_addr(environ):
415 def get_ip_addr(environ):
306 proxy_key = 'HTTP_X_REAL_IP'
416 proxy_key = 'HTTP_X_REAL_IP'
307 proxy_key2 = 'HTTP_X_FORWARDED_FOR'
417 proxy_key2 = 'HTTP_X_FORWARDED_FOR'
308 def_key = 'REMOTE_ADDR'
418 def_key = 'REMOTE_ADDR'
309 _filters = lambda x: _filter_port(_filter_proxy(x))
419
420 def _filters(x):
421 return _filter_port(_filter_proxy(x))
310
422
311 ip = environ.get(proxy_key)
423 ip = environ.get(proxy_key)
312 if ip:
424 if ip:
313 return _filters(ip)
425 return _filters(ip)
314
426
315 ip = environ.get(proxy_key2)
427 ip = environ.get(proxy_key2)
316 if ip:
428 if ip:
317 return _filters(ip)
429 return _filters(ip)
318
430
319 ip = environ.get(def_key, '0.0.0.0')
431 ip = environ.get(def_key, '0.0.0.0')
320 return _filters(ip)
432 return _filters(ip)
321
433
322
434
323 class RhodeCodeLogger(Logger):
435 class RhodeCodeLogger(Logger):
324 """
436 """
325 Custom Logger that allows some customization that gunicorn doesn't allow
437 Custom Logger that allows some customization that gunicorn doesn't allow
326 """
438 """
327
439
328 datefmt = r"%Y-%m-%d %H:%M:%S"
440 datefmt = r"%Y-%m-%d %H:%M:%S"
329
441
330 def __init__(self, cfg):
442 def __init__(self, cfg):
331 Logger.__init__(self, cfg)
443 Logger.__init__(self, cfg)
332
444
333 def now(self):
445 def now(self):
334 """ return date in RhodeCode Log format """
446 """ return date in RhodeCode Log format """
335 now = time.time()
447 now = time.time()
336 msecs = int((now - int(now)) * 1000)
448 msecs = int((now - int(now)) * 1000)
337 return time.strftime(self.datefmt, time.localtime(now)) + '.{0:03d}'.format(msecs)
449 return time.strftime(self.datefmt, time.localtime(now)) + '.{0:03d}'.format(msecs)
338
450
339 def atoms(self, resp, req, environ, request_time):
451 def atoms(self, resp, req, environ, request_time):
340 """ Gets atoms for log formatting.
452 """ Gets atoms for log formatting.
341 """
453 """
342 status = resp.status
454 status = resp.status
343 if isinstance(status, str):
455 if isinstance(status, str):
344 status = status.split(None, 1)[0]
456 status = status.split(None, 1)[0]
345 atoms = {
457 atoms = {
346 'h': get_ip_addr(environ),
458 'h': get_ip_addr(environ),
347 'l': '-',
459 'l': '-',
348 'u': self._get_user(environ) or '-',
460 'u': self._get_user(environ) or '-',
349 't': self.now(),
461 't': self.now(),
350 'r': "%s %s %s" % (environ['REQUEST_METHOD'],
462 'r': "%s %s %s" % (environ['REQUEST_METHOD'],
351 environ['RAW_URI'],
463 environ['RAW_URI'],
352 environ["SERVER_PROTOCOL"]),
464 environ["SERVER_PROTOCOL"]),
353 's': status,
465 's': status,
354 'm': environ.get('REQUEST_METHOD'),
466 'm': environ.get('REQUEST_METHOD'),
355 'U': environ.get('PATH_INFO'),
467 'U': environ.get('PATH_INFO'),
356 'q': environ.get('QUERY_STRING'),
468 'q': environ.get('QUERY_STRING'),
357 'H': environ.get('SERVER_PROTOCOL'),
469 'H': environ.get('SERVER_PROTOCOL'),
358 'b': getattr(resp, 'sent', None) is not None and str(resp.sent) or '-',
470 'b': getattr(resp, 'sent', None) is not None and str(resp.sent) or '-',
359 'B': getattr(resp, 'sent', None),
471 'B': getattr(resp, 'sent', None),
360 'f': environ.get('HTTP_REFERER', '-'),
472 'f': environ.get('HTTP_REFERER', '-'),
361 'a': environ.get('HTTP_USER_AGENT', '-'),
473 'a': environ.get('HTTP_USER_AGENT', '-'),
362 'T': request_time.seconds,
474 'T': request_time.seconds,
363 'D': (request_time.seconds * 1000000) + request_time.microseconds,
475 'D': (request_time.seconds * 1000000) + request_time.microseconds,
364 'M': (request_time.seconds * 1000) + int(request_time.microseconds/1000),
476 'M': (request_time.seconds * 1000) + int(request_time.microseconds/1000),
365 'L': "%d.%06d" % (request_time.seconds, request_time.microseconds),
477 'L': "%d.%06d" % (request_time.seconds, request_time.microseconds),
366 'p': "<%s>" % os.getpid()
478 'p': "<%s>" % os.getpid()
367 }
479 }
368
480
369 # add request headers
481 # add request headers
370 if hasattr(req, 'headers'):
482 if hasattr(req, 'headers'):
371 req_headers = req.headers
483 req_headers = req.headers
372 else:
484 else:
373 req_headers = req
485 req_headers = req
374
486
375 if hasattr(req_headers, "items"):
487 if hasattr(req_headers, "items"):
376 req_headers = req_headers.items()
488 req_headers = req_headers.items()
377
489
378 atoms.update({"{%s}i" % k.lower(): v for k, v in req_headers})
490 atoms.update({"{%s}i" % k.lower(): v for k, v in req_headers})
379
491
380 resp_headers = resp.headers
492 resp_headers = resp.headers
381 if hasattr(resp_headers, "items"):
493 if hasattr(resp_headers, "items"):
382 resp_headers = resp_headers.items()
494 resp_headers = resp_headers.items()
383
495
384 # add response headers
496 # add response headers
385 atoms.update({"{%s}o" % k.lower(): v for k, v in resp_headers})
497 atoms.update({"{%s}o" % k.lower(): v for k, v in resp_headers})
386
498
387 # add environ variables
499 # add environ variables
388 environ_variables = environ.items()
500 environ_variables = environ.items()
389 atoms.update({"{%s}e" % k.lower(): v for k, v in environ_variables})
501 atoms.update({"{%s}e" % k.lower(): v for k, v in environ_variables})
390
502
391 return atoms
503 return atoms
392
504
505
393 logger_class = RhodeCodeLogger
506 logger_class = RhodeCodeLogger
@@ -1,238 +1,167 b''
1 #
1 #
2
2
3 ; #################################
3 ; #################################
4 ; RHODECODE VCSSERVER CONFIGURATION
4 ; RHODECODE VCSSERVER CONFIGURATION
5 ; #################################
5 ; #################################
6
6
7 [server:main]
7 [server:main]
8 ; COMMON HOST/IP CONFIG
8 ; COMMON HOST/IP CONFIG
9 host = 127.0.0.1
9 host = 127.0.0.1
10 port = 9900
10 port = 10010
11
11
12
12
13 ; ###########################
13 ; ###########################
14 ; GUNICORN APPLICATION SERVER
14 ; GUNICORN APPLICATION SERVER
15 ; ###########################
15 ; ###########################
16
16
17 ; run with gunicorn --paste rhodecode.ini
17 ; run with gunicorn --paste rhodecode.ini
18
18
19 ; Module to use, this setting shouldn't be changed
19 ; Module to use, this setting shouldn't be changed
20 use = egg:gunicorn#main
20 use = egg:gunicorn#main
21
21
22 ; Sets the number of process workers. More workers means more concurrent connections
23 ; RhodeCode can handle at the same time. Each additional worker also it increases
24 ; memory usage as each has it's own set of caches.
25 ; Recommended value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers, but no more
26 ; than 8-10 unless for really big deployments .e.g 700-1000 users.
27 ; `instance_id = *` must be set in the [app:main] section below (which is the default)
28 ; when using more than 1 worker.
29 workers = 2
30
31 ; Gunicorn access log level
32 loglevel = info
33
34 ; Process name visible in process list
35 proc_name = rhodecode_vcsserver
36
37 ; Type of worker class, one of `sync`, `gevent`
38 ; currently `sync` is the only option allowed.
39 worker_class = sync
40
41 ; The maximum number of simultaneous clients. Valid only for gevent
42 worker_connections = 10
43
44 ; Max number of requests that worker will handle before being gracefully restarted.
45 ; Prevents memory leaks, jitter adds variability so not all workers are restarted at once.
46 max_requests = 1000
47 max_requests_jitter = 30
48
49 ; Amount of time a worker can spend with handling a request before it
50 ; gets killed and restarted. By default set to 21600 (6hrs)
51 ; Examples: 1800 (30min), 3600 (1hr), 7200 (2hr), 43200 (12h)
52 timeout = 21600
53
54 ; The maximum size of HTTP request line in bytes.
55 ; 0 for unlimited
56 limit_request_line = 0
57
58 ; Limit the number of HTTP headers fields in a request.
59 ; By default this value is 100 and can't be larger than 32768.
60 limit_request_fields = 32768
61
62 ; Limit the allowed size of an HTTP request header field.
63 ; Value is a positive number or 0.
64 ; Setting it to 0 will allow unlimited header field sizes.
65 limit_request_field_size = 0
66
67 ; Timeout for graceful workers restart.
68 ; After receiving a restart signal, workers have this much time to finish
69 ; serving requests. Workers still alive after the timeout (starting from the
70 ; receipt of the restart signal) are force killed.
71 ; Examples: 1800 (30min), 3600 (1hr), 7200 (2hr), 43200 (12h)
72 graceful_timeout = 21600
73
74 # The number of seconds to wait for requests on a Keep-Alive connection.
75 # Generally set in the 1-5 seconds range.
76 keepalive = 2
77
78 ; Maximum memory usage that each worker can use before it will receive a
79 ; graceful restart signal 0 = memory monitoring is disabled
80 ; Examples: 268435456 (256MB), 536870912 (512MB)
81 ; 1073741824 (1GB), 2147483648 (2GB), 4294967296 (4GB)
82 memory_max_usage = 0
83
84 ; How often in seconds to check for memory usage for each gunicorn worker
85 memory_usage_check_interval = 60
86
87 ; Threshold value for which we don't recycle worker if GarbageCollection
88 ; frees up enough resources. Before each restart we try to run GC on worker
89 ; in case we get enough free memory after that, restart will not happen.
90 memory_usage_recovery_threshold = 0.8
91
92
93 [app:main]
22 [app:main]
94 ; The %(here)s variable will be replaced with the absolute path of parent directory
23 ; The %(here)s variable will be replaced with the absolute path of parent directory
95 ; of this file
24 ; of this file
96 ; Each option in the app:main can be override by an environmental variable
25 ; Each option in the app:main can be override by an environmental variable
97 ;
26 ;
98 ;To override an option:
27 ;To override an option:
99 ;
28 ;
100 ;RC_<KeyName>
29 ;RC_<KeyName>
101 ;Everything should be uppercase, . and - should be replaced by _.
30 ;Everything should be uppercase, . and - should be replaced by _.
102 ;For example, if you have these configuration settings:
31 ;For example, if you have these configuration settings:
103 ;rc_cache.repo_object.backend = foo
32 ;rc_cache.repo_object.backend = foo
104 ;can be overridden by
33 ;can be overridden by
105 ;export RC_CACHE_REPO_OBJECT_BACKEND=foo
34 ;export RC_CACHE_REPO_OBJECT_BACKEND=foo
106
35
107 use = egg:rhodecode-vcsserver
36 use = egg:rhodecode-vcsserver
108
37
109 ; Pyramid default locales, we need this to be set
38 ; Pyramid default locales, we need this to be set
110 #pyramid.default_locale_name = en
39 #pyramid.default_locale_name = en
111
40
112 ; default locale used by VCS systems
41 ; default locale used by VCS systems
113 #locale = en_US.UTF-8
42 #locale = en_US.UTF-8
114
43
115 ; path to binaries for vcsserver, it should be set by the installer
44 ; path to binaries for vcsserver, it should be set by the installer
116 ; at installation time, e.g /home/user/.rccontrol/vcsserver-1/profile/bin
45 ; at installation time, e.g /home/user/.rccontrol/vcsserver-1/profile/bin
117 ; it can also be a path to nix-build output in case of development
46 ; it can also be a path to nix-build output in case of development
118 core.binary_dir = ""
47 core.binary_dir = ""
119
48
120 ; Custom exception store path, defaults to TMPDIR
49 ; Custom exception store path, defaults to TMPDIR
121 ; This is used to store exception from RhodeCode in shared directory
50 ; This is used to store exception from RhodeCode in shared directory
122 #exception_tracker.store_path =
51 #exception_tracker.store_path =
123
52
124 ; #############
53 ; #############
125 ; DOGPILE CACHE
54 ; DOGPILE CACHE
126 ; #############
55 ; #############
127
56
128 ; Default cache dir for caches. Putting this into a ramdisk can boost performance.
57 ; Default cache dir for caches. Putting this into a ramdisk can boost performance.
129 ; eg. /tmpfs/data_ramdisk, however this directory might require large amount of space
58 ; eg. /tmpfs/data_ramdisk, however this directory might require large amount of space
130 #cache_dir = %(here)s/data
59 #cache_dir = %(here)s/data
131
60
132 ; ***************************************
61 ; ***************************************
133 ; `repo_object` cache, default file based
62 ; `repo_object` cache, default file based
134 ; ***************************************
63 ; ***************************************
135
64
136 ; `repo_object` cache settings for vcs methods for repositories
65 ; `repo_object` cache settings for vcs methods for repositories
137 #rc_cache.repo_object.backend = dogpile.cache.rc.file_namespace
66 #rc_cache.repo_object.backend = dogpile.cache.rc.file_namespace
138
67
139 ; cache auto-expires after N seconds
68 ; cache auto-expires after N seconds
140 ; Examples: 86400 (1Day), 604800 (7Days), 1209600 (14Days), 2592000 (30days), 7776000 (90Days)
69 ; Examples: 86400 (1Day), 604800 (7Days), 1209600 (14Days), 2592000 (30days), 7776000 (90Days)
141 #rc_cache.repo_object.expiration_time = 2592000
70 #rc_cache.repo_object.expiration_time = 2592000
142
71
143 ; file cache store path. Defaults to `cache_dir =` value or tempdir if both values are not set
72 ; file cache store path. Defaults to `cache_dir =` value or tempdir if both values are not set
144 #rc_cache.repo_object.arguments.filename = /tmp/vcsserver_cache_repo_object.db
73 #rc_cache.repo_object.arguments.filename = /tmp/vcsserver_cache_repo_object.db
145
74
146 ; ***********************************************************
75 ; ***********************************************************
147 ; `repo_object` cache with redis backend
76 ; `repo_object` cache with redis backend
148 ; recommended for larger instance, and for better performance
77 ; recommended for larger instance, and for better performance
149 ; ***********************************************************
78 ; ***********************************************************
150
79
151 ; `repo_object` cache settings for vcs methods for repositories
80 ; `repo_object` cache settings for vcs methods for repositories
152 #rc_cache.repo_object.backend = dogpile.cache.rc.redis_msgpack
81 #rc_cache.repo_object.backend = dogpile.cache.rc.redis_msgpack
153
82
154 ; cache auto-expires after N seconds
83 ; cache auto-expires after N seconds
155 ; Examples: 86400 (1Day), 604800 (7Days), 1209600 (14Days), 2592000 (30days), 7776000 (90Days)
84 ; Examples: 86400 (1Day), 604800 (7Days), 1209600 (14Days), 2592000 (30days), 7776000 (90Days)
156 #rc_cache.repo_object.expiration_time = 2592000
85 #rc_cache.repo_object.expiration_time = 2592000
157
86
158 ; redis_expiration_time needs to be greater then expiration_time
87 ; redis_expiration_time needs to be greater then expiration_time
159 #rc_cache.repo_object.arguments.redis_expiration_time = 3592000
88 #rc_cache.repo_object.arguments.redis_expiration_time = 3592000
160
89
161 #rc_cache.repo_object.arguments.host = localhost
90 #rc_cache.repo_object.arguments.host = localhost
162 #rc_cache.repo_object.arguments.port = 6379
91 #rc_cache.repo_object.arguments.port = 6379
163 #rc_cache.repo_object.arguments.db = 5
92 #rc_cache.repo_object.arguments.db = 5
164 #rc_cache.repo_object.arguments.socket_timeout = 30
93 #rc_cache.repo_object.arguments.socket_timeout = 30
165 ; more Redis options: https://dogpilecache.sqlalchemy.org/en/latest/api.html#redis-backends
94 ; more Redis options: https://dogpilecache.sqlalchemy.org/en/latest/api.html#redis-backends
166 #rc_cache.repo_object.arguments.distributed_lock = true
95 #rc_cache.repo_object.arguments.distributed_lock = true
167
96
168 ; auto-renew lock to prevent stale locks, slower but safer. Use only if problems happen
97 ; auto-renew lock to prevent stale locks, slower but safer. Use only if problems happen
169 #rc_cache.repo_object.arguments.lock_auto_renewal = true
98 #rc_cache.repo_object.arguments.lock_auto_renewal = true
170
99
171 ; Statsd client config, this is used to send metrics to statsd
100 ; Statsd client config, this is used to send metrics to statsd
172 ; We recommend setting statsd_exported and scrape them using Promethues
101 ; We recommend setting statsd_exported and scrape them using Promethues
173 #statsd.enabled = false
102 #statsd.enabled = false
174 #statsd.statsd_host = 0.0.0.0
103 #statsd.statsd_host = 0.0.0.0
175 #statsd.statsd_port = 8125
104 #statsd.statsd_port = 8125
176 #statsd.statsd_prefix =
105 #statsd.statsd_prefix =
177 #statsd.statsd_ipv6 = false
106 #statsd.statsd_ipv6 = false
178
107
179 ; configure logging automatically at server startup set to false
108 ; configure logging automatically at server startup set to false
180 ; to use the below custom logging config.
109 ; to use the below custom logging config.
181 ; RC_LOGGING_FORMATTER
110 ; RC_LOGGING_FORMATTER
182 ; RC_LOGGING_LEVEL
111 ; RC_LOGGING_LEVEL
183 ; env variables can control the settings for logging in case of autoconfigure
112 ; env variables can control the settings for logging in case of autoconfigure
184
113
185 #logging.autoconfigure = true
114 #logging.autoconfigure = true
186
115
187 ; specify your own custom logging config file to configure logging
116 ; specify your own custom logging config file to configure logging
188 #logging.logging_conf_file = /path/to/custom_logging.ini
117 #logging.logging_conf_file = /path/to/custom_logging.ini
189
118
190 ; #####################
119 ; #####################
191 ; LOGGING CONFIGURATION
120 ; LOGGING CONFIGURATION
192 ; #####################
121 ; #####################
193
122
194 [loggers]
123 [loggers]
195 keys = root, vcsserver
124 keys = root, vcsserver
196
125
197 [handlers]
126 [handlers]
198 keys = console
127 keys = console
199
128
200 [formatters]
129 [formatters]
201 keys = generic, json
130 keys = generic, json
202
131
203 ; #######
132 ; #######
204 ; LOGGERS
133 ; LOGGERS
205 ; #######
134 ; #######
206 [logger_root]
135 [logger_root]
207 level = NOTSET
136 level = NOTSET
208 handlers = console
137 handlers = console
209
138
210 [logger_vcsserver]
139 [logger_vcsserver]
211 level = INFO
140 level = INFO
212 handlers =
141 handlers =
213 qualname = vcsserver
142 qualname = vcsserver
214 propagate = 1
143 propagate = 1
215
144
216 ; ########
145 ; ########
217 ; HANDLERS
146 ; HANDLERS
218 ; ########
147 ; ########
219
148
220 [handler_console]
149 [handler_console]
221 class = StreamHandler
150 class = StreamHandler
222 args = (sys.stderr, )
151 args = (sys.stderr, )
223 level = INFO
152 level = INFO
224 ; To enable JSON formatted logs replace 'generic' with 'json'
153 ; To enable JSON formatted logs replace 'generic' with 'json'
225 ; This allows sending properly formatted logs to grafana loki or elasticsearch
154 ; This allows sending properly formatted logs to grafana loki or elasticsearch
226 formatter = generic
155 formatter = generic
227
156
228 ; ##########
157 ; ##########
229 ; FORMATTERS
158 ; FORMATTERS
230 ; ##########
159 ; ##########
231
160
232 [formatter_generic]
161 [formatter_generic]
233 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
162 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
234 datefmt = %Y-%m-%d %H:%M:%S
163 datefmt = %Y-%m-%d %H:%M:%S
235
164
236 [formatter_json]
165 [formatter_json]
237 format = %(timestamp)s %(levelname)s %(name)s %(message)s %(req_id)s
166 format = %(timestamp)s %(levelname)s %(name)s %(message)s %(req_id)s
238 class = vcsserver.lib._vendor.jsonlogger.JsonFormatter
167 class = vcsserver.lib._vendor.jsonlogger.JsonFormatter
General Comments 0
You need to be logged in to leave comments. Login now