talentro-commons 0.20.4__tar.gz → 0.20.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/PKG-INFO +1 -1
  2. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/pyproject.toml +1 -1
  3. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/services/rabbitmq.py +39 -54
  4. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/README.md +0 -0
  5. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/__init__.py +0 -0
  6. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/acquisition/__init__.py +0 -0
  7. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/acquisition/dataclasses.py +0 -0
  8. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/acquisition/models.py +0 -0
  9. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/billing/__init__.py +0 -0
  10. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/billing/dataclasses.py +0 -0
  11. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/billing/models.py +0 -0
  12. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/candidates/__init__.py +0 -0
  13. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/candidates/dataclasses.py +0 -0
  14. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/candidates/models.py +0 -0
  15. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/constants.py +0 -0
  16. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/event.py +0 -0
  17. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/exceptions.py +0 -0
  18. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/general/__init__.py +0 -0
  19. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/general/dataclasses.py +0 -0
  20. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/general/models.py +0 -0
  21. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/iam/__init__.py +0 -0
  22. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/iam/dataclasses.py +0 -0
  23. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/iam/models.py +0 -0
  24. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/iam/types.py +0 -0
  25. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/integrations/__init__.py +0 -0
  26. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/integrations/dataclasses.py +0 -0
  27. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/integrations/models.py +0 -0
  28. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/messaging/__init__.py +0 -0
  29. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/messaging/topology.py +0 -0
  30. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/services/__init__.py +0 -0
  31. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/services/billing.py +0 -0
  32. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/services/caching.py +0 -0
  33. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/services/clients.py +0 -0
  34. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/services/db.py +0 -0
  35. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/services/google_storage.py +0 -0
  36. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/util/__init__.py +0 -0
  37. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/util/attributes.py +0 -0
  38. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/util/enum.py +0 -0
  39. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/util/files.py +0 -0
  40. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/util/singleton.py +0 -0
  41. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/util/string.py +0 -0
  42. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/util/vacancy.py +0 -0
  43. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/vacancies/__init__.py +0 -0
  44. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/vacancies/dataclasses.py +0 -0
  45. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/vacancies/models.py +0 -0
  46. {talentro_commons-0.20.4 → talentro_commons-0.20.6}/src/talentro/vacancies/taxanomy.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: talentro-commons
3
- Version: 0.20.4
3
+ Version: 0.20.6
4
4
  Summary: This package contains all globally used code, services, models and data structures for Talentro
5
5
  License: Proprietary
6
6
  Author: Emiel van Essen
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "talentro-commons"
3
- version = "0.20.4"
3
+ version = "0.20.6"
4
4
  description = "This package contains all globally used code, services, models and data structures for Talentro"
5
5
  authors = ["Emiel van Essen <emiel@marksmen.nl>"]
6
6
  license = "Proprietary"
@@ -100,12 +100,12 @@ class RabbitMQ:
100
100
  f"(TTL: {ttl_ms}ms)")
101
101
 
102
102
  async def consume(
103
- self,
104
- exchange_name: str,
105
- queue: str,
106
- callback: Callable,
107
- dlx_name: Optional[str] = None,
108
- max_retries: int = 3
103
+ self,
104
+ exchange_name: str,
105
+ queue: str,
106
+ callback: Callable,
107
+ dlx_name: Optional[str] = None,
108
+ max_retries: int = 3
109
109
  ):
110
110
  while True:
111
111
  try:
@@ -125,62 +125,40 @@ class RabbitMQ:
125
125
 
126
126
  async for message in queue_object:
127
127
  try:
128
- async with message.process():
128
+ # Use ignore_processed=True to prevent auto-ack on successful processing
129
+ async with message.process(ignore_processed=True, requeue=False):
129
130
  event: Event = Event.decode(message.body)
130
- print(f" RabbitMQ ({queue}) - [x] Received event: {event.meta.event_type} (trace: {event.meta.trace_id})")
131
+ print(
132
+ f" RabbitMQ ({queue}) - [x] Received event: {event.meta.event_type} (trace: {event.meta.trace_id})")
131
133
  await callback(queue, event)
134
+ # If we reach here, callback succeeded - manually ack
135
+ await message.ack()
132
136
  except Exception as e:
133
137
  # Handle callback exception - send to retry queue
134
138
  print(f" RabbitMQ ({queue}) - ⚠️ Error processing message: {e}")
135
139
  traceback.print_exc()
136
- await self._handle_failed_message(message, queue, exchange_name, dlx_name, max_retries)
140
+
141
+ # Get retry count from headers
142
+ x_death = message.headers.get('x-death', [])
143
+ death_count = len(x_death) if x_death else 0
144
+
145
+ print(f" RabbitMQ ({queue}) - Retry attempt {death_count + 1}/{max_retries + 1}")
146
+
147
+ if death_count >= max_retries:
148
+ print(f" RabbitMQ ({queue}) - ❌ Max retries ({max_retries}) exceeded. Sending to DLQ.")
149
+ await message.nack(requeue=False)
150
+ else:
151
+ print(f" RabbitMQ ({queue}) - Sending to retry queue...")
152
+ await message.nack(requeue=False)
137
153
 
138
154
  except (aio_pika.exceptions.AMQPConnectionError, aio_pika.exceptions.ChannelClosed):
139
155
  print(f" RabbitMQ - Connection lost while consuming {queue}. Retrying in 5 seconds...")
140
156
  await asyncio.sleep(5)
141
157
  except Exception as e:
142
158
  print(f" RabbitMQ - Unexpected error in consumer {queue}: {e}")
159
+ traceback.print_exc()
143
160
  await asyncio.sleep(5)
144
161
 
145
- @staticmethod
146
- async def _handle_failed_message(
147
- message: aio_pika.IncomingMessage,
148
- queue_name: str,
149
- exchange_name: str,
150
- dlx_name: Optional[str] = None,
151
- max_retries: int = 3
152
- ):
153
- """
154
- Handle failed messages by sending them to the retry queue or DLQ.
155
- """
156
- try:
157
- # Get death count from headers
158
- x_death = message.headers.get('x-death', [])
159
- death_count = 0
160
-
161
- if x_death:
162
- # x-death is a list of death info dicts
163
- death_count = len(x_death)
164
-
165
- print(f" RabbitMQ ({queue_name}) - Retry attempt {death_count + 1}/{max_retries + 1}")
166
-
167
- if death_count >= max_retries:
168
- # Max retries exceeded - send to DLQ
169
- print(f" RabbitMQ ({queue_name}) - ❌ Max retries ({max_retries}) exceeded. Sending to DLQ.")
170
- await message.nack(requeue=False)
171
- else:
172
- # Still have retries left - send to retry queue
173
- if dlx_name:
174
- await message.nack(requeue=False)
175
- print(f" RabbitMQ ({queue_name}) - Sending to retry queue...")
176
- else:
177
- await message.nack(requeue=True)
178
- print(f" RabbitMQ ({queue_name}) - Message requeued")
179
-
180
- except Exception as e:
181
- print(f" RabbitMQ ({queue_name}) - Error handling failed message: {e}")
182
- await message.nack(requeue=False)
183
-
184
162
  async def send_message(self, message: Message):
185
163
  # Haal de exchange op
186
164
  if message.exchange == "default":
@@ -210,7 +188,7 @@ class QueueContext(metaclass=SingletonMeta):
210
188
  def __init__(self):
211
189
  self._rabbit_mq = RabbitMQ()
212
190
  self._message_callbacks = []
213
- self._topology_config: TopologyConfig | None = None
191
+ self._topology_configs: dict[str, TopologyConfig] = {} # Store all topologies
214
192
 
215
193
  async def connect(self):
216
194
  try:
@@ -227,7 +205,8 @@ class QueueContext(metaclass=SingletonMeta):
227
205
  await self._setup_topology_with_config(topology)
228
206
 
229
207
  async def _setup_topology_with_config(self, topology_config: TopologyConfig):
230
- self._topology_config = topology_config
208
+ # Sla topology op met exchange_name als key
209
+ self._topology_configs[topology_config.exchange_name] = topology_config
231
210
 
232
211
  await self._rabbit_mq.setup_topology(
233
212
  topology_config.exchange_name,
@@ -237,15 +216,21 @@ class QueueContext(metaclass=SingletonMeta):
237
216
  retry_config=topology_config.retry_config
238
217
  )
239
218
 
240
- async def start_consuming(self, queue: str):
241
- max_retries = self._topology_config.get_max_retries(queue) if self._topology_config else 3
219
+
220
+ async def start_consuming(self, queue: str, exchange_name: str):
221
+ topology_config = self._topology_configs.get(exchange_name)
222
+
223
+ if not topology_config:
224
+ raise ValueError(f"Topology not found for exchange: {exchange_name}")
225
+
226
+ max_retries = topology_config.get_max_retries(queue)
242
227
 
243
228
  asyncio.create_task(
244
229
  self._rabbit_mq.consume(
245
- self._topology_config.exchange_name,
230
+ exchange_name,
246
231
  queue,
247
232
  self._on_new_message,
248
- dlx_name=self._topology_config.dlx_name,
233
+ dlx_name=topology_config.dlx_name,
249
234
  max_retries=max_retries
250
235
  )
251
236
  )