Skip to content

Commit 83f462d

Browse files
authored
Merge pull request #59 from cloudblue/feature/LITE-21474
LITE-21474 Added optional cqrs-id argument to consume command
2 parents 3a6b631 + c98c401 commit 83f462d

File tree

6 files changed

+129
-40
lines changed

6 files changed

+129
-40
lines changed

dj_cqrs/management/commands/cqrs_consume.py

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,50 @@
22

33
from multiprocessing import Process
44

5+
from dj_cqrs.registries import ReplicaRegistry
56
from dj_cqrs.transport import current_transport
67

7-
from django.core.management.base import BaseCommand
8+
from django.core.management.base import BaseCommand, CommandError
89

910

1011
class Command(BaseCommand):
1112
help = 'Starts CQRS worker, which consumes messages from message queue.'
1213

1314
def add_arguments(self, parser):
1415
parser.add_argument('--workers', '-w', help='Number of workers', type=int, default=0)
16+
parser.add_argument(
17+
'--cqrs-id',
18+
'-cid',
19+
nargs='*',
20+
type=str,
21+
help='Choose model(s) by CQRS_ID for consuming',
22+
)
1523

1624
def handle(self, *args, **options):
17-
if options['workers'] == 0:
18-
current_transport.consume()
19-
else:
20-
pool = []
21-
22-
for _ in range(options['workers']):
23-
p = Process(target=current_transport.consume)
24-
pool.append(p)
25-
p.start()
26-
27-
for p in pool:
28-
p.join()
25+
consume_kwargs = {}
26+
27+
if options.get('cqrs_id'):
28+
cqrs_ids = set()
29+
30+
for cqrs_id in options['cqrs_id']:
31+
model = ReplicaRegistry.get_model_by_cqrs_id(cqrs_id)
32+
if not model:
33+
raise CommandError('Wrong CQRS ID: {0}!'.format(cqrs_id))
34+
35+
cqrs_ids.add(cqrs_id)
36+
37+
consume_kwargs['cqrs_ids'] = cqrs_ids
38+
39+
if options['workers'] <= 1:
40+
current_transport.consume(**consume_kwargs)
41+
return
42+
43+
pool = []
44+
45+
for _ in range(options['workers']):
46+
p = Process(target=current_transport.consume, kwargs=consume_kwargs)
47+
pool.append(p)
48+
p.start()
49+
50+
for p in pool:
51+
p.join()

dj_cqrs/transport/kombu.py

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
class _KombuConsumer(ConsumerMixin):
2525

26-
def __init__(self, url, exchange_name, queue_name, prefetch_count, callback):
26+
def __init__(self, url, exchange_name, queue_name, prefetch_count, callback, cqrs_ids=None):
2727
self.connection = Connection(url)
2828
self.exchange = Exchange(
2929
exchange_name,
@@ -34,28 +34,31 @@ def __init__(self, url, exchange_name, queue_name, prefetch_count, callback):
3434
self.prefetch_count = prefetch_count
3535
self.callback = callback
3636
self.queues = []
37+
self.cqrs_ids = cqrs_ids
38+
3739
self._init_queues()
3840

3941
def _init_queues(self):
4042
channel = self.connection.channel()
4143
for cqrs_id in ReplicaRegistry.models.keys():
42-
q = Queue(
43-
self.queue_name,
44-
exchange=self.exchange,
45-
routing_key=cqrs_id,
46-
)
47-
q.maybe_bind(channel)
48-
q.declare()
49-
self.queues.append(q)
50-
51-
sync_q = Queue(
52-
self.queue_name,
53-
exchange=self.exchange,
54-
routing_key='cqrs.{0}.{1}'.format(self.queue_name, cqrs_id),
55-
)
56-
sync_q.maybe_bind(channel)
57-
sync_q.declare()
58-
self.queues.append(sync_q)
44+
if (not self.cqrs_ids) or (cqrs_id in self.cqrs_ids):
45+
q = Queue(
46+
self.queue_name,
47+
exchange=self.exchange,
48+
routing_key=cqrs_id,
49+
)
50+
q.maybe_bind(channel)
51+
q.declare()
52+
self.queues.append(q)
53+
54+
sync_q = Queue(
55+
self.queue_name,
56+
exchange=self.exchange,
57+
routing_key='cqrs.{0}.{1}'.format(self.queue_name, cqrs_id),
58+
)
59+
sync_q.maybe_bind(channel)
60+
sync_q.declare()
61+
self.queues.append(sync_q)
5962

6063
def get_consumers(self, Consumer, channel):
6164
return [
@@ -77,7 +80,7 @@ def clean_connection(cls):
7780
pass
7881

7982
@classmethod
80-
def consume(cls):
83+
def consume(cls, cqrs_ids=None):
8184
queue_name, prefetch_count = cls._get_consumer_settings()
8285
url, exchange_name = cls._get_common_settings()
8386

@@ -87,6 +90,7 @@ def consume(cls):
8790
queue_name,
8891
prefetch_count,
8992
cls._consume_message,
93+
cqrs_ids=cqrs_ids,
9094
)
9195
consumer.run()
9296

dj_cqrs/transport/mock.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright © 2020 Ingram Micro Inc. All rights reserved.
1+
# Copyright © 2021 Ingram Micro Inc. All rights reserved.
22

33
from dj_cqrs.transport import BaseTransport
44

@@ -9,5 +9,5 @@ def produce(payload):
99
return TransportMock.consume(payload)
1010

1111
@staticmethod
12-
def consume(payload):
12+
def consume(payload=None, **kwargs):
1313
return payload

dj_cqrs/transport/rabbit_mq.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def clean_connection(cls):
4545
cls._producer_channel = None
4646

4747
@classmethod
48-
def consume(cls):
48+
def consume(cls, cqrs_ids=None):
4949
consumer_rabbit_settings = cls._get_consumer_settings()
5050
common_rabbit_settings = cls._get_common_settings()
5151

@@ -54,7 +54,7 @@ def consume(cls):
5454
try:
5555
delay_queue = DelayQueue(max_size=get_delay_queue_max_size())
5656
connection, channel, consumer_generator = cls._get_consumer_rmq_objects(
57-
*(common_rabbit_settings + consumer_rabbit_settings),
57+
*(common_rabbit_settings + consumer_rabbit_settings), cqrs_ids=cqrs_ids,
5858
)
5959

6060
for method_frame, properties, body in consumer_generator:
@@ -239,7 +239,15 @@ def _get_produced_message_routing_key(cls, payload):
239239

240240
@classmethod
241241
def _get_consumer_rmq_objects(
242-
cls, host, port, creds, exchange, queue_name, dead_letter_queue_name, prefetch_count,
242+
cls,
243+
host,
244+
port,
245+
creds,
246+
exchange,
247+
queue_name,
248+
dead_letter_queue_name,
249+
prefetch_count,
250+
cqrs_ids=None,
243251
):
244252
connection = BlockingConnection(
245253
ConnectionParameters(host=host, port=port, credentials=creds),
@@ -252,6 +260,9 @@ def _get_consumer_rmq_objects(
252260
channel.queue_declare(dead_letter_queue_name, durable=True, exclusive=False)
253261

254262
for cqrs_id, _ in ReplicaRegistry.models.items():
263+
if cqrs_ids and cqrs_id not in cqrs_ids:
264+
continue
265+
255266
channel.queue_bind(exchange=exchange, queue=queue_name, routing_key=cqrs_id)
256267

257268
# Every service must have specific SYNC or requeue routes

tests/dj/transport.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright © 2020 Ingram Micro Inc. All rights reserved.
1+
# Copyright © 2021 Ingram Micro Inc. All rights reserved.
22

33
import os
44

@@ -14,8 +14,9 @@ def produce(payload):
1414
TransportStub.consume(payload)
1515

1616
@staticmethod
17-
def consume(payload):
18-
consumer.consume(payload)
17+
def consume(payload=None):
18+
if payload:
19+
return consumer.consume(payload)
1920

2021

2122
class RabbitMQTransportWithEvents(RabbitMQTransport):
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Copyright © 2021 Ingram Micro Inc. All rights reserved.
2+
3+
from importlib import import_module, reload
4+
5+
from django.core.management import CommandError, call_command
6+
7+
import pytest
8+
9+
10+
COMMAND_NAME = 'cqrs_consume'
11+
12+
13+
@pytest.fixture
14+
def reload_transport():
15+
reload(import_module('dj_cqrs.transport'))
16+
17+
18+
def test_no_arguments(mocker, reload_transport):
19+
consume_mock = mocker.patch('tests.dj.transport.TransportStub.consume')
20+
21+
call_command(COMMAND_NAME)
22+
23+
consume_mock.assert_called_once_with()
24+
25+
26+
def test_several_workers(reload_transport):
27+
call_command(COMMAND_NAME, '--workers=2')
28+
29+
30+
def test_one_worker_one_cqrs_id(mocker, reload_transport):
31+
consume_mock = mocker.patch('tests.dj.transport.TransportStub.consume')
32+
33+
call_command(COMMAND_NAME, '--workers=1', '-cid=author')
34+
35+
consume_mock.assert_called_once_with(cqrs_ids={'author'})
36+
37+
38+
def test_several_cqrs_id(mocker, reload_transport):
39+
consume_mock = mocker.patch('tests.dj.transport.TransportStub.consume')
40+
41+
call_command(COMMAND_NAME, cqrs_id=['author', 'basic', 'author', 'no_db'])
42+
43+
consume_mock.assert_called_once_with(cqrs_ids={'author', 'basic', 'no_db'})
44+
45+
46+
def test_wrong_cqrs_id(reload_transport):
47+
with pytest.raises(CommandError) as e:
48+
call_command(COMMAND_NAME, cqrs_id=['author', 'random', 'no_db'])
49+
50+
assert "Wrong CQRS ID: random!" in str(e)

0 commit comments

Comments
 (0)