Only reload apache only when strictly necessary

This commit is contained in:
Marc Aymerich 2015-04-12 18:18:10 +00:00
parent 79ae1a79b0
commit 525d38750e
8 changed files with 48 additions and 39 deletions

12
TODO.md
View file

@ -286,6 +286,14 @@ https://code.djangoproject.com/ticket/24576
# Change crons, create cron for deleted webapps and users
* UNIFY PHP FPM settings name
# virtualhost name name-account?
# php version update should trigger webiste upgrade (wrapper name/fpm config for apache), public root and other config also needs apache to execute
* add a delay to changes on the webserver apache to no overwelm it with backend executions?
# Delete webapps deletes wrapper that may be used for other sites, maybe merging webapps is a bad idea after all?
* replace unique_name by natural_key?
* do not require contact or create default
* send signals for backend triggers
* monitor resources with multiple backends not possible to identify the correct last execution, allow to specify backends only once or change backend.model = 'resources.MonitorData'
* force ignore slack billing period overridig when billing
* fpm reload starts new pools?
* more processes for webmail, or use fpm pool
* rename resource.monitors to resource.backends ?
* abstract model classes enabling overriding?

View file

@ -142,27 +142,28 @@ def collect(instance, action, **kwargs):
operations = kwargs.get('operations', set())
route_cache = kwargs.get('route_cache', {})
for backend_cls in ServiceBackend.get_backends():
# Check if there exists a related instance to be executed for this backend
# Check if there exists a related instance to be executed for this backend and action
instances = []
if backend_cls.is_main(instance):
instances = [(instance, action)]
else:
candidate = backend_cls.get_related(instance)
if candidate:
if candidate.__class__.__name__ == 'ManyRelatedManager':
if 'pk_set' in kwargs:
# m2m_changed signal
candidates = kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
if action in backend_cls.actions:
if backend_cls.is_main(instance):
instances = [(instance, action)]
else:
candidate = backend_cls.get_related(instance)
if candidate:
if candidate.__class__.__name__ == 'ManyRelatedManager':
if 'pk_set' in kwargs:
# m2m_changed signal
candidates = kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
else:
candidates = candidate.all()
else:
candidates = candidate.all()
else:
candidates = [candidate]
for candidate in candidates:
# Check if a delete for candidate is in operations
delete_mock = Operation(backend_cls, candidate, Operation.DELETE)
if delete_mock not in operations:
# related objects with backend.model trigger save()
instances.append((candidate, Operation.SAVE))
candidates = [candidate]
for candidate in candidates:
# Check if a delete for candidate is in operations
delete_mock = Operation(backend_cls, candidate, Operation.DELETE)
if delete_mock not in operations:
# related objects with backend.model trigger save()
instances.append((candidate, Operation.SAVE))
for selected, iaction in instances:
# Maintain consistent state of operations based on save/delete behaviour
# Prevent creating a deleted selected by deleting existing saves

View file

@ -10,11 +10,9 @@ def run_monitor(modeladmin, request, queryset):
async = modeladmin.model.monitor.__defaults__[0]
logs = set()
for resource in queryset:
results = resource.monitor()
rlogs = resource.monitor()
if not async:
for result in results:
if hasattr(result, 'log'):
logs.add(str(result.log.pk))
logs = logs.union(set([str(rlog.pk) for rlog in rlogs]))
modeladmin.log_change(request, resource, _("Run monitors"))
if async:
num = len(queryset)

View file

@ -42,7 +42,7 @@ class ServiceMonitor(ServiceBackend):
from .models import MonitorData
try:
return MonitorData.objects.filter(content_type=self.content_type,
object_id=object_id).latest()
monitor=type(self).get_name(), object_id=object_id).latest()
except MonitorData.DoesNotExist:
return None

View file

@ -12,7 +12,7 @@ def monitor(resource_id, ids=None, async=True):
resource = Resource.objects.get(pk=resource_id)
resource_model = resource.content_type.model_class()
operations = []
logs = []
# Execute monitors
for monitor_name in resource.monitors:
backend = ServiceMonitor.get_backend(monitor_name)
@ -28,10 +28,9 @@ def monitor(resource_id, ids=None, async=True):
monitorings = []
for obj in model.objects.filter(**kwargs):
op = Operation(backend, obj, Operation.MONITOR)
operations.append(op)
monitorings.append(op)
# TODO async=True only when running with celery
Operation.execute(monitorings, async=async)
logs += Operation.execute(monitorings, async=async)
kwargs = {'id__in': ids} if ids else {}
# Update used resources and trigger resource exceeded and revovery
@ -50,4 +49,4 @@ def monitor(resource_id, ids=None, async=True):
op = Operation(backend, obj, Operation.RECOVERY)
triggers.append(op)
Operation.execute(triggers)
return operations
return logs

View file

@ -33,7 +33,7 @@ class PHPBackend(WebAppServiceMixin, ServiceController):
echo -e "${fpm_config}" | diff -N -I'^\s*;;' %(fpm_path)s -
} || {
echo -e "${fpm_config}" > %(fpm_path)s
UPDATEDFPM=1
UPDATED_FPM=1
}
""") % context
)
@ -46,7 +46,10 @@ class PHPBackend(WebAppServiceMixin, ServiceController):
echo -e "${wrapper}" | diff -N -I'^\s*#' %(wrapper_path)s -
} || {
echo -e "${wrapper}" > %(wrapper_path)s
[[ ${UPDATED_APACHE} -eq 0 ]] && UPDATED_APACHE=%(is_mounted)i
if [[ %(is_mounted)i -eq 1 ]]; then
# Reload fcgid wrapper
pkill -SIGHUP -U %(user)s "^%(php_binary)s$" || true
fi
}
""") % context
)
@ -93,15 +96,14 @@ class PHPBackend(WebAppServiceMixin, ServiceController):
def commit(self):
self.append(textwrap.dedent("""
if [[ $UPDATEDFPM == 1 ]]; then
if [[ $UPDATED_FPM -eq 1 ]]; then
service php5-fpm reload
service php5-fpm start
fi
# Coordinate apache restart with apache backend
locked=1
state="$(grep -v 'PHPBackend' /dev/shm/restart.apache2)" || locked=0
echo -n "$state" > /dev/shm/restart.apache2
if [[ $UPDATED_APACHE == 1 ]]; then
if [[ $UPDATED_APACHE -eq 1 ]]; then
if [[ $locked == 0 ]]; then
service apache2 reload
else
@ -151,18 +153,19 @@ class PHPBackend(WebAppServiceMixin, ServiceController):
init_vars = [ "-d %s='%s'" % (k, v.replace("'", '"')) for k,v in init_vars.items() ]
init_vars = ' \\\n '.join(init_vars)
context.update({
'php_binary': os.path.normpath(settings.WEBAPPS_PHP_CGI_BINARY_PATH % context),
'php_binary_path': os.path.normpath(settings.WEBAPPS_PHP_CGI_BINARY_PATH % context),
'php_rc': os.path.normpath(settings.WEBAPPS_PHP_CGI_RC_DIR % context),
'php_ini_scan': os.path.normpath(settings.WEBAPPS_PHP_CGI_INI_SCAN_DIR % context),
'php_init_vars': init_vars,
})
context['php_binary'] = os.path.basename(context['php_binary_path'])
return textwrap.dedent("""\
#!/bin/sh
# %(banner)s
export PHPRC=%(php_rc)s
export PHP_INI_SCAN_DIR=%(php_ini_scan)s
export PHP_FCGI_MAX_REQUESTS=%(max_requests)s
exec %(php_binary)s %(php_init_vars)s""") % context
exec %(php_binary_path)s %(php_init_vars)s""") % context
def get_fcgid_cmd_options(self, webapp, context):
maps = {

View file

@ -88,7 +88,7 @@ class Processes(AppOption):
# FPM pm.max_children
verbose_name = _("Number of processes")
help_text = _("Maximum number of children that can be alive at the same time (a number between 0 and 9).")
regex = r'^[0-9]$'
regex = r'^[0-9]{1,2}$'
group = AppOption.PROCESS

View file

@ -49,7 +49,7 @@
<div id="branding"><a href="/admin/"></a><h1 id="site-name"><a href="/admin/">Pangea Hosting Management <span class="version">0.0.1a1</span></a></h1></div>
{% for item in menu.children %}{% admin_tools_render_menu_item item forloop.counter %}{% endfor %}
<span style="float:right;color:grey;padding:10px;font-size:11px;">{% trans 'Welcome' %},
{% url 'admin:users_user_change' user.pk as user_change_url %}
{% url 'admin:accounts_account_change' user.pk as user_change_url %}
<a href="{{ user_change_url }}" style="color:#555;"><strong>{% filter force_escape %}{% firstof user.get_short_name user.username %}{% endfilter %}</strong></a>.
<a href="{% url 'admin:password_change' %}" style="color:#555;">Change password</a> / <a href="{% url 'admin:logout' %}" style="color:#555;">Log out</a></span>
</div>