Clone database connection on manager.execute
This commit is contained in:
parent
c5140ccbae
commit
6fa29a15b8
2
TODO.md
2
TODO.md
|
@ -355,3 +355,5 @@ make django admin taskstate uncollapse fucking traceback, ( if exists ?)
|
|||
# backend.context and backned.instance provided when an action is called? like forms.cleaned_data: do it on manager.generation(backend.context = backend.get_context()) or in backend.__getattr__ ? also backend.head,tail,content switching on manager.generate()?
|
||||
|
||||
# replace return_code by exit_code everywhere
|
||||
|
||||
# plan.rate registry
|
||||
|
|
|
@ -167,7 +167,11 @@ class ServiceBackend(plugins.Plugin, metaclass=ServiceMount):
|
|||
run = bool(self.scripts) or (self.force_empty_action_execution or bool(self.content))
|
||||
if not run:
|
||||
state = BackendLog.NOTHING
|
||||
log = BackendLog.objects.create(backend=self.get_name(), state=state, server=server)
|
||||
using = kwargs.pop('using', None)
|
||||
manager = BackendLog.objects
|
||||
if using:
|
||||
manager = manager.using(using)
|
||||
log = manager.create(backend=self.get_name(), state=state, server=server)
|
||||
return log
|
||||
|
||||
def execute(self, server, async=False, log=None):
|
||||
|
|
|
@ -6,7 +6,7 @@ from functools import partial
|
|||
|
||||
from django.core.mail import mail_admins
|
||||
|
||||
from orchestra.utils.db import close_connection
|
||||
from orchestra.utils import db
|
||||
from orchestra.utils.python import import_class, OrderedSet
|
||||
|
||||
from . import settings, Operation
|
||||
|
@ -31,7 +31,7 @@ def keep_log(execute, log, operations):
|
|||
send_report(execute, args, log)
|
||||
except Exception as e:
|
||||
trace = traceback.format_exc()
|
||||
log.state = BackendLog.EXCEPTION
|
||||
log.state = log.EXCEPTION
|
||||
log.stderr = trace
|
||||
log.save()
|
||||
subject = 'EXCEPTION executing backend(s) %s %s' % (str(args), str(kwargs))
|
||||
|
@ -122,12 +122,9 @@ def execute(scripts, serialize=False, async=None):
|
|||
kwargs = {
|
||||
'async': async,
|
||||
}
|
||||
log = backend.create_log(*args, **kwargs)
|
||||
# TODO Perform this shit outside of the current transaction in a non-hacky way
|
||||
#t = threading.Thread(target=backend.create_log, args=args, kwargs=kwargs)
|
||||
#t.start()
|
||||
#log = t.join()
|
||||
# End of hack
|
||||
with db.clone(model=BackendLog) as handle:
|
||||
log = backend.create_log(*args, using=handle.target)
|
||||
log._state.db = handle.origin
|
||||
kwargs['log'] = log
|
||||
task = keep_log(backend.execute, log, operations)
|
||||
logger.debug('%s is going to be executed on %s.' % (backend, route.host))
|
||||
|
@ -135,7 +132,7 @@ def execute(scripts, serialize=False, async=None):
|
|||
# Execute one backend at a time, no need for threads
|
||||
task(*args, **kwargs)
|
||||
else:
|
||||
task = close_connection(task)
|
||||
task = db.close_connection(task)
|
||||
thread = threading.Thread(target=task, args=args, kwargs=kwargs)
|
||||
thread.start()
|
||||
if not async:
|
||||
|
|
|
@ -28,6 +28,7 @@ def grant_permission(modeladmin, request, queryset):
|
|||
for user in queryset:
|
||||
user.grant_to = to
|
||||
user.grant_ro = ro
|
||||
# DOn't collect, execute right away for path validation
|
||||
OperationsMiddleware.collect('grant_permission', instance=user)
|
||||
context = {
|
||||
'type': _("read-only") if ro else _("read-write"),
|
||||
|
@ -35,6 +36,7 @@ def grant_permission(modeladmin, request, queryset):
|
|||
}
|
||||
msg = _("Granted %(type)s permissions on %(to)s") % context
|
||||
modeladmin.log_change(request, user, msg)
|
||||
# TODO feedback message
|
||||
return
|
||||
opts = modeladmin.model._meta
|
||||
app_label = opts.app_label
|
||||
|
|
|
@ -72,7 +72,7 @@ class UNIXUserBackend(ServiceController):
|
|||
'to': user.grant_to,
|
||||
'ro': user.grant_ro,
|
||||
})
|
||||
if user.ro:
|
||||
if user.grant_ro:
|
||||
self.append('echo "acl add read permissions for %(user)s to %(to)s"' % context)
|
||||
else:
|
||||
self.append('echo "acl add read-write permissions for %(user)s to %(to)s"' % context)
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
<div class="field-box field-home">
|
||||
{{ form.path_extension.errors }}
|
||||
<label for="{{ form.base_path.id_for_label }}">{{ form.base_path.label }}:</label>
|
||||
{{ form.base_path }}
|
||||
{{ form.base_path }}{% for x in ""|ljust:"50" %} {% endfor %}
|
||||
<p class="help">{{ form.base_path.help_text|safe }}</p>
|
||||
</div>
|
||||
<div class="field-box field-home">
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import sys
|
||||
|
||||
from django import db
|
||||
from django.conf import settings as djsettings
|
||||
|
||||
|
||||
def running_syncdb():
|
||||
|
@ -31,3 +32,31 @@ def close_connection(execute):
|
|||
finally:
|
||||
db.connection.close()
|
||||
return wrapper
|
||||
|
||||
|
||||
class clone(object):
|
||||
"""
|
||||
clone database in order to have fresh connections and make queries outside the current transaction
|
||||
|
||||
with db.clone(model=BackendLog) as handle:
|
||||
log = BackendLog.objects.using(handle.target).create()
|
||||
log._state.db = handle.origin
|
||||
|
||||
"""
|
||||
def __init__(self, model=None, origin='', target=''):
|
||||
if model is not None:
|
||||
origin = db.router.db_for_write(model)
|
||||
self.origin = origin or db.DEFAULT_DB_ALIAS
|
||||
self.target = target or 'other_' + origin
|
||||
|
||||
def __enter__(self):
|
||||
djsettings.DATABASES[self.target] = djsettings.DATABASES[self.origin]
|
||||
# Because db.connections.datases is a cached property
|
||||
self.old_connections = db.connections
|
||||
db.connections = db.utils.ConnectionHandler()
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
db.connections[self.target].close()
|
||||
djsettings.DATABASES.pop(self.target)
|
||||
db.connections = self.old_connections
|
||||
|
|
Loading…
Reference in New Issue