Skip to content

Commit 4cd6aed

Browse files
author
Sergio García Prado
authored
Merge pull request #356 from minos-framework/0.6.1
0.6.1
2 parents 72cd513 + b86750e commit 4cd6aed

File tree

10 files changed

+141
-30
lines changed

10 files changed

+141
-30
lines changed

packages/core/minos-microservice-common/HISTORY.md

+51-1
Original file line numberDiff line numberDiff line change
@@ -308,4 +308,54 @@ History
308308
* Add `Object` base class with the purpose to avoid issues related with multi-inheritance and mixins.
309309
* Add `Port` base class as the base class for ports.
310310
* Add `CircuitBreakerMixin` class to provide circuit breaker functionalities.
311-
* Add `SetupMixin` class as a replacement of the `MinosSetup` class.
311+
* Add `SetupMixin` class as a replacement of the `MinosSetup` class.
312+
313+
### Update Guide (from 0.5.x to 0.6.0)
314+
315+
* Add `@Injectable` decorator to classes that injections:
316+
317+
```python
318+
from minos.common import Injectable
319+
320+
321+
@Injectable("THE_INJECTION_NAME")
322+
class MyInjectableClass:
323+
...
324+
```
325+
326+
* Add `minos-http-aiohttp` package:
327+
328+
```shell
329+
poetry add minos-http-aiohttp@^0.6
330+
```
331+
332+
* Add `HttpConnector` instance to `service.injections` section of `config.yml` file:
333+
334+
```yaml
335+
...
336+
service:
337+
injections:
338+
http_connector: minos.plugins.aiohttp.AioHttpConnector
339+
...
340+
...
341+
...
342+
```
343+
344+
* Add `routers` section to `config.yml` file:
345+
346+
```yaml
347+
...
348+
routers:
349+
- minos.networks.BrokerRouter
350+
- minos.networks.PeriodicRouter
351+
- minos.networks.RestHttpRouter
352+
...
353+
```
354+
355+
* Update `minos.common.Config` usages according to the new provided API:
356+
* Most common issues come from calls like `config.query_repository._asdict()`, that must be transformed to `config.get_database_by_name("query")`
357+
358+
0.6.1 (2022-04-01)
359+
------------------
360+
361+
* Fix bug that didn't show the correct exception traceback when microservice failures occurred.

packages/core/minos-microservice-common/minos/common/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
__author__ = "Minos Framework Devs"
22
__email__ = "[email protected]"
3-
__version__ = "0.6.0"
3+
__version__ = "0.6.1"
44

55
from .builders import (
66
BuildableMixin,

packages/core/minos-microservice-common/minos/common/launchers.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ def launch(self) -> NoReturn:
134134
logger.info("Stopping microservice...")
135135
exception = exc
136136
except Exception as exc: # pragma: no cover
137+
logger.exception("Stopping microservice due to an unhandled exception...")
137138
exception = exc
138139
finally:
139140
self.graceful_shutdown(exception)
@@ -143,14 +144,14 @@ def graceful_launch(self) -> None:
143144
144145
:return: This method does not return anything.
145146
"""
146-
self.loop.run_until_complete(gather(self.setup(), self.entrypoint.__aenter__()))
147+
self.loop.run_until_complete(self.setup())
147148

148149
def graceful_shutdown(self, err: Exception = None) -> None:
149150
"""Shutdown the execution gracefully.
150151
151152
:return: This method does not return anything.
152153
"""
153-
self.loop.run_until_complete(gather(self.entrypoint.__aexit__(None, err, None), self.destroy()))
154+
self.loop.run_until_complete(self.destroy())
154155

155156
@cached_property
156157
def entrypoint(self) -> Entrypoint:
@@ -199,9 +200,10 @@ async def _setup(self) -> None:
199200
200201
:return: This method does not return anything.
201202
"""
202-
await self.injector.wire_and_setup_injections(
203-
modules=self._external_modules + self._internal_modules, packages=self._external_packages
204-
)
203+
modules = self._external_modules + self._internal_modules
204+
packages = self._external_packages
205+
self.injector.wire_injections(modules=modules, packages=packages)
206+
await gather(self.injector.setup_injections(), self.entrypoint.__aenter__())
205207

206208
@property
207209
def _internal_modules(self) -> list[ModuleType]:
@@ -212,7 +214,8 @@ async def _destroy(self) -> None:
212214
213215
:return: This method does not return anything.
214216
"""
215-
await self.injector.unwire_and_destroy_injections()
217+
await gather(self.entrypoint.__aexit__(None, None, None), self.injector.destroy_injections())
218+
self.injector.unwire_injections()
216219

217220
@property
218221
def injections(self) -> dict[str, InjectableMixin]:

packages/core/minos-microservice-common/pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "minos-microservice-common"
3-
version = "0.6.0"
3+
version = "0.6.1"
44
description = "The common core of the Minos Framework"
55
readme = "README.md"
66
repository = "https://github.com/minos-framework/minos-python"

packages/core/minos-microservice-common/tests/test_common/test_launchers.py

+48-17
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import warnings
33
from unittest.mock import (
44
AsyncMock,
5+
MagicMock,
56
call,
67
patch,
78
)
@@ -106,37 +107,67 @@ async def test_loop(self):
106107
self.assertEqual(call(), mock_loop.call_args)
107108

108109
async def test_setup(self):
109-
mock = AsyncMock()
110-
self.launcher.injector.wire_and_setup_injections = mock
111-
await self.launcher.setup()
110+
wire_mock = MagicMock()
111+
setup_mock = AsyncMock()
112+
mock_entrypoint_aenter = AsyncMock()
113+
114+
self.launcher.injector.wire_injections = wire_mock
115+
self.launcher.injector.setup_injections = setup_mock
116+
117+
with patch("minos.common.launchers._create_loop") as mock_loop:
118+
loop = FakeLoop()
119+
mock_loop.return_value = loop
120+
with patch("minos.common.launchers._create_entrypoint") as mock_entrypoint:
121+
entrypoint = FakeEntrypoint()
122+
mock_entrypoint.return_value = entrypoint
123+
124+
entrypoint.__aenter__ = mock_entrypoint_aenter
125+
126+
await self.launcher.setup()
112127

113-
self.assertEqual(1, mock.call_count)
128+
self.assertEqual(1, wire_mock.call_count)
114129
import tests
115130
from minos import (
116131
common,
117132
)
118133

119-
self.assertEqual(0, len(mock.call_args.args))
120-
self.assertEqual(2, len(mock.call_args.kwargs))
121-
observed = mock.call_args.kwargs["modules"]
134+
self.assertEqual(0, len(wire_mock.call_args.args))
135+
self.assertEqual(2, len(wire_mock.call_args.kwargs))
136+
observed = wire_mock.call_args.kwargs["modules"]
122137

123138
self.assertIn(tests, observed)
124139
self.assertIn(common, observed)
125140

126-
self.assertEqual(["tests"], mock.call_args.kwargs["packages"])
141+
self.assertEqual(["tests"], wire_mock.call_args.kwargs["packages"])
127142

128-
await self.launcher.destroy()
143+
self.assertEqual(1, setup_mock.call_count)
144+
self.assertEqual(1, mock_entrypoint_aenter.call_count)
129145

130146
async def test_destroy(self):
131-
self.launcher.injector.wire_and_setup_injections = AsyncMock()
147+
self.launcher._setup = AsyncMock()
132148
await self.launcher.setup()
133149

134-
mock = AsyncMock()
135-
self.launcher.injector.unwire_and_destroy_injections = mock
136-
await self.launcher.destroy()
150+
destroy_mock = AsyncMock()
151+
unwire_mock = MagicMock()
152+
mock_entrypoint_aexit = AsyncMock()
153+
154+
self.launcher.injector.destroy_injections = destroy_mock
155+
self.launcher.injector.unwire_injections = unwire_mock
156+
157+
with patch("minos.common.launchers._create_loop") as mock_loop:
158+
loop = FakeLoop()
159+
mock_loop.return_value = loop
160+
with patch("minos.common.launchers._create_entrypoint") as mock_entrypoint:
161+
entrypoint = FakeEntrypoint()
162+
mock_entrypoint.return_value = entrypoint
163+
164+
entrypoint.__aexit__ = mock_entrypoint_aexit
165+
166+
await self.launcher.destroy()
137167

138-
self.assertEqual(1, mock.call_count)
139-
self.assertEqual(call(), mock.call_args)
168+
self.assertEqual(1, unwire_mock.call_count)
169+
self.assertEqual(1, destroy_mock.call_count)
170+
self.assertEqual(1, mock_entrypoint_aexit.call_count)
140171

141172
def test_launch(self):
142173
mock_setup = AsyncMock()
@@ -157,8 +188,8 @@ def test_launch(self):
157188

158189
self.launcher.launch()
159190

160-
self.assertEqual(1, mock_entrypoint.call_count)
161-
self.assertEqual(1, mock_loop.call_count)
191+
self.assertEqual(1, mock_setup.call_count)
192+
self.assertEqual(1, mock_destroy.call_count)
162193

163194

164195
class TestEntryPointLauncherLoop(unittest.TestCase):

packages/plugins/minos-broker-kafka/HISTORY.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,8 @@
1818
## 0.6.0 (2022-03-28)
1919

2020
* Add `KafkaCircuitBreakerMixin` to integrate `minos.common.CircuitBreakerMixin` into the `KafkaBrokerPublisher` and `KafkaBrokerSubscriber` classes to be tolerant to connection failures to `kafka`.
21-
* Add `KafkaBrokerPublisherBuilder` and `KafkaBrokerBuilderMixin` classes to ease the building process.
21+
* Add `KafkaBrokerPublisherBuilder` and `KafkaBrokerBuilderMixin` classes to ease the building process.
22+
23+
## 0.6.1 (2022-04-01)
24+
25+
* Improve `KafkaBrokerSubscriber`'s destroying process.

packages/plugins/minos-broker-kafka/minos/plugins/kafka/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
__author__ = "Minos Framework Devs"
22
__email__ = "[email protected]"
3-
__version__ = "0.6.0"
3+
__version__ = "0.6.1"
44

55
from .common import (
66
KafkaBrokerBuilderMixin,

packages/plugins/minos-broker-kafka/minos/plugins/kafka/subscriber.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
from aiokafka import (
2424
AIOKafkaConsumer,
25+
ConsumerStoppedError,
2526
)
2627
from cached_property import (
2728
cached_property,
@@ -166,7 +167,12 @@ def admin_client(self):
166167
return KafkaAdminClient(bootstrap_servers=f"{self.host}:{self.port}")
167168

168169
async def _receive(self) -> BrokerMessage:
169-
record = await self.client.getone()
170+
try:
171+
record = await self.client.getone()
172+
except ConsumerStoppedError as exc:
173+
if self.already_destroyed:
174+
raise StopAsyncIteration
175+
raise exc
170176
bytes_ = record.value
171177
message = BrokerMessage.from_avro_bytes(bytes_)
172178
return message

packages/plugins/minos-broker-kafka/pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "minos-broker-kafka"
3-
version = "0.6.0"
3+
version = "0.6.1"
44
description = "The kafka plugin of the Minos Framework"
55
readme = "README.md"
66
repository = "https://github.com/minos-framework/minos-python"

packages/plugins/minos-broker-kafka/tests/test_kafka/test_subscriber.py

+17
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from aiokafka import (
1212
AIOKafkaConsumer,
13+
ConsumerStoppedError,
1314
)
1415
from kafka import (
1516
KafkaAdminClient,
@@ -206,6 +207,22 @@ async def test_receive(self):
206207
self.assertEqual(messages[0], await subscriber.receive())
207208
self.assertEqual(messages[1], await subscriber.receive())
208209

210+
async def test_receive_already_stopped_raises(self):
211+
subscriber = KafkaBrokerSubscriber.from_config(CONFIG_FILE_PATH, topics={"foo", "bar"})
212+
get_mock = AsyncMock(side_effect=ConsumerStoppedError)
213+
subscriber.client.getone = get_mock
214+
215+
with self.assertRaises(StopAsyncIteration):
216+
await subscriber.receive()
217+
218+
async def test_receive_stopped(self):
219+
async with KafkaBrokerSubscriber.from_config(CONFIG_FILE_PATH, topics={"foo", "bar"}) as subscriber:
220+
get_mock = AsyncMock(side_effect=ConsumerStoppedError)
221+
subscriber.client.getone = get_mock
222+
223+
with self.assertRaises(ConsumerStoppedError):
224+
await subscriber.receive()
225+
209226

210227
class TestKafkaBrokerSubscriberBuilder(unittest.TestCase):
211228
def setUp(self) -> None:

0 commit comments

Comments
 (0)