0001-don-t-start-a-new-cron-if-locked-18519.patch
tests/test_publisher.py | ||
---|---|---|
8 | 8 |
import zipfile |
9 | 9 | |
10 | 10 |
import mock |
11 |
import pytest |
|
11 | 12 | |
12 | 13 |
from django.core.management import call_command |
14 |
from django.core.management.base import CommandError |
|
13 | 15 |
from quixote import cleanup |
14 | 16 |
from wcs.qommon.http_request import HTTPRequest |
15 | 17 | |
... | ... | |
172 | 174 |
with mock.patch('wcs.qommon.management.commands.cron.cron_worker') as cron_worker: |
173 | 175 |
call_command('cron') |
174 | 176 |
assert cron_worker.call_count == 1 |
177 | ||
178 |
# simulate another locked cron |
|
179 |
import tempfile |
|
180 |
from qommon.vendor import locket |
|
181 |
lockfile = os.path.join(tempfile.gettempdir(), 'wcs-cron-in-progress.lock') |
|
182 |
with locket.lock_file(lockfile, timeout=0): |
|
183 |
with mock.patch('wcs.qommon.management.commands.cron.cron_worker') as cron_worker: |
|
184 |
call_command('cron') # silent by default (verbosity=0) |
|
185 |
assert cron_worker.call_count == 0 |
|
186 |
with pytest.raises(CommandError, match='can not start cron job, locked'): |
|
187 |
call_command('cron', verbosity=1) # CommandError with verbosity>0 |
|
188 |
assert cron_worker.call_count == 0 |
|
189 |
# verify that the lock is released |
|
190 |
with mock.patch('wcs.qommon.management.commands.cron.cron_worker') as cron_worker: |
|
191 |
call_command('cron') |
|
192 |
assert cron_worker.call_count == 1 |
|
193 | ||
194 |
# simulate a cron crash |
|
195 |
with mock.patch('wcs.qommon.management.commands.cron.cron_worker') as cron_worker: |
|
196 |
cron_worker.side_effect = NotImplementedError |
|
197 |
with pytest.raises(NotImplementedError): |
|
198 |
call_command('cron') |
|
199 |
assert cron_worker.call_count == 1 |
|
200 |
# verify that the lock is released |
|
201 |
with mock.patch('wcs.qommon.management.commands.cron.cron_worker') as cron_worker: |
|
202 |
call_command('cron') |
|
203 |
assert cron_worker.call_count == 1 |
wcs/qommon/management/commands/cron.py | ||
---|---|---|
18 | 18 |
import time |
19 | 19 |
import os |
20 | 20 | |
21 |
from django.core.management.base import BaseCommand |
|
21 |
from django.core.management.base import BaseCommand, CommandError
|
|
22 | 22 |
from qommon.publisher import get_publisher_class |
23 | 23 | |
24 |
from qommon import get_logger, get_publisher |
|
24 | 25 |
from qommon.vendor import locket |
25 | 26 |
from qommon.cron import cron_worker |
26 | 27 | |
... | ... | |
28 | 29 |
class Command(BaseCommand): |
29 | 30 |
help = 'Execute cronjobs' |
30 | 31 | |
31 |
def handle(self, verbosity, **options): |
|
32 |
with locket.lock_file(os.path.join(tempfile.gettempdir(), 'wcs-cron')): |
|
33 |
now = time.localtime() |
|
34 |
publisher_class = get_publisher_class() |
|
35 |
publisher_class.register_cronjobs() |
|
36 |
publisher = publisher_class.create_publisher() |
|
37 |
app_dir = publisher.app_dir |
|
38 |
for hostname in publisher.get_tenants(): |
|
39 |
publisher.app_dir = os.path.join(app_dir, hostname) |
|
40 |
cron_worker(publisher, now) |
|
32 |
def add_arguments(self, parser): |
|
33 |
super(Command, self).add_arguments(parser) |
|
34 |
parser.set_defaults(verbosity=0) |
|
35 | ||
36 |
def handle(self, verbosity, **kwargs): |
|
37 |
lockfile = os.path.join(tempfile.gettempdir(), 'wcs-cron-in-progress.lock') |
|
38 |
try: |
|
39 |
with locket.lock_file(lockfile, timeout=0): |
|
40 |
now = time.localtime() |
|
41 |
publisher_class = get_publisher_class() |
|
42 |
publisher_class.register_cronjobs() |
|
43 |
publisher = publisher_class.create_publisher() |
|
44 |
app_dir = publisher.app_dir |
|
45 |
for hostname in publisher.get_tenants(): |
|
46 |
publisher.app_dir = os.path.join(app_dir, hostname) |
|
47 |
cron_worker(publisher, now) |
|
48 |
except locket.LockError: |
|
49 |
if verbosity > 0: |
|
50 |
raise CommandError('can not start cron job, locked by %s' % lockfile) |
|
41 |
- |