misc: use hobo.multitenant.spooler (#76747) #55

Open
bdauvergne wants to merge 1 commits from wip/76747-utiliser-hobo-multitenant-spoole into main
6 changed files with 57 additions and 92 deletions

1
debian/control vendored
View File

@ -31,7 +31,6 @@ Depends: python3-django-mellon,
python3-hobo,
python3-lingo (= ${binary:Version}),
python3-psycopg2,
python3-uwsgidecorators,
uwsgi,
uwsgi-plugin-python3,
${misc:Depends},

2
debian/uwsgi.ini vendored
View File

@ -14,7 +14,7 @@ vacuum = true
spooler-processes = 3
spooler-python-import = lingo.invoicing.spooler
spooler-python-import = hobo.provisionning.spooler
spooler-python-import = hobo.multitenant.spooler
spooler-max-tasks = 20
master = true

View File

@ -15,13 +15,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import copy
import sys
import traceback
from django.conf import settings
from django.contrib.auth.models import Group
from django.core.serializers.json import DjangoJSONEncoder
from django.db import connection, models, transaction
from django.db import models, transaction
from django.utils.formats import date_format
from django.utils.text import slugify
from django.utils.timezone import now
@ -29,6 +28,7 @@ from django.utils.translation import gettext_lazy as _
from lingo.agendas.chrono import ChronoError, lock_events_check
from lingo.agendas.models import Agenda
from lingo.utils import spooler
from lingo.utils.misc import generate_slug
@ -171,18 +171,10 @@ class Campaign(models.Model):
except Exception:
return
if spool and 'uwsgi' in sys.modules:
from lingo.invoicing.spooler import generate_invoices
tenant = getattr(connection, 'tenant', None)
transaction.on_commit(
lambda: generate_invoices.spool(
campaign_id=str(self.pk), pool_id=str(pool.pk), domain=getattr(tenant, 'domain_url', None)
)
)
return
pool.generate_invoices()
if spool:
spooler.run(pool.generate_invoices)
else:
pool.generate_invoices()
class Pool(models.Model):
@ -275,20 +267,30 @@ class Pool(models.Model):
final_pool.completed_at = None
final_pool.save()
if 'uwsgi' in sys.modules:
from lingo.invoicing.spooler import populate_from_draft
spooler.run(final_pool.populate_from_draft_spooler, self)
tenant = getattr(connection, 'tenant', None)
transaction.on_commit(
lambda: populate_from_draft.spool(
draft_pool_id=str(self.pk),
final_pool_id=str(final_pool.pk),
domain=getattr(tenant, 'domain_url', None),
)
)
def populate_from_draft_spooler(self, draft_pool):
# we may be in the spooler, refresh our view of the instances, they
# could no exist anymore
try:
draft_pool.refresh_from_db()
self.refresh_from_db()
except Pool.DoesNotExist:
return
final_pool.populate_from_draft(self)
# FIXME: needs comment for why we do all those checks, they were
# already needed before in the spooler function
if draft_pool.status != 'completed' or not draft_pool.draft:
return
if draft_pool.campaign.pool_set.filter(created_at__gt=draft_pool.created_at, draft=True).exists():
return
# check final_pool = self
if self.status != 'registered' or self.draft:
return
self.populate_from_draft(draft_pool)
def populate_from_draft(self, draft_pool):
try:

View File

@ -1,65 +0,0 @@
# lingo - payment and billing system
# Copyright (C) 2023 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.db import connection
from uwsgidecorators import spool # pylint: disable=import-error
from lingo.invoicing.models import Pool
def set_connection(domain):
from hobo.multitenant.middleware import TenantMiddleware # pylint: disable=import-error
tenant = TenantMiddleware.get_tenant_by_hostname(domain)
connection.set_tenant(tenant)
@spool
def generate_invoices(args):
if args.get('domain'):
# multitenant installation
set_connection(args['domain'])
try:
pool = Pool.objects.get(
campaign__pk=args['campaign_id'], pk=args['pool_id'], status='registered', draft=True
)
except Pool.DoesNotExist:
return
pool.generate_invoices()
@spool
def populate_from_draft(args):
if args.get('domain'):
# multitenant installation
set_connection(args['domain'])
try:
draft_pool = Pool.objects.get(pk=args['draft_pool_id'], status='completed', draft=True)
except Pool.DoesNotExist:
return
if draft_pool.campaign.pool_set.filter(created_at__gt=draft_pool.created_at, draft=True).exists():
return
try:
final_pool = Pool.objects.get(pk=args['final_pool_id'], status='registered', draft=False)
except Pool.DoesNotExist:
return
final_pool.populate_from_draft(draft_pool)

View File

@ -202,6 +202,8 @@ DEBUG_TOOLBAR_CONFIG = {'SHOW_TOOLBAR_CALLBACK': debug_show_toolbar}
REST_FRAMEWORK = {'EXCEPTION_HANDLER': 'lingo.api.utils.exception_handler'}
USE_NEW_SPOOLER = True
local_settings_file = os.environ.get(
'LINGO_SETTINGS_FILE', os.path.join(os.path.dirname(__file__), 'local_settings.py')
)

27
lingo/utils/spooler.py Normal file
View File

@ -0,0 +1,27 @@
# lingo - payment and billing system
# Copyright (C) 2023 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
try:
from hobo.multitenant.spooler import run # pylint: disable=unused-import
except ImportError:
import pickle
def run(func, *args, **kwargs):
try:
pickle.dumps((func, args, kwargs))
except Exception:
raise ValueError(f'{(func, args, kwargs)} are unpicklable')
func(*args, **kwargs)