fdc-shared-kernel 0.0.32__tar.gz → 0.0.34__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 (63) hide show
  1. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/PKG-INFO +1 -1
  2. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/fdc_shared_kernel.egg-info/PKG-INFO +1 -1
  3. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/fdc_shared_kernel.egg-info/SOURCES.txt +1 -0
  4. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/pyproject.toml +1 -1
  5. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/logger/__init__.py +11 -5
  6. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/messaging/__init__.py +7 -1
  7. fdc_shared_kernel-0.0.34/shared_kernel/messaging/event_bridge_sqs_databus.py +162 -0
  8. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/README.md +0 -0
  9. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/README_pypi.md +0 -0
  10. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/fdc_shared_kernel.egg-info/dependency_links.txt +0 -0
  11. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/fdc_shared_kernel.egg-info/requires.txt +0 -0
  12. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/fdc_shared_kernel.egg-info/top_level.txt +0 -0
  13. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/requirements.txt +0 -0
  14. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/setup.cfg +0 -0
  15. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/__init__.py +0 -0
  16. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/async_task_executor/__init__.py +0 -0
  17. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/async_task_executor/async_task_executor.py +0 -0
  18. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/auth/__init__.py +0 -0
  19. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/auth/jwt_helper.py +0 -0
  20. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/auth/token_handler.py +0 -0
  21. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/config/__init__.py +0 -0
  22. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/database/__init__.py +0 -0
  23. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/enums/__init__.py +0 -0
  24. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/enums/async_task_status.py +0 -0
  25. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/exceptions/__init__.py +0 -0
  26. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/exceptions/configuration_exceptions.py +0 -0
  27. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/exceptions/custom_exceptions.py +0 -0
  28. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/exceptions/data_validation_exceptions.py +0 -0
  29. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/exceptions/http_exceptions.py +0 -0
  30. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/exceptions/infrastructure_exceptions.py +0 -0
  31. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/exceptions/operational_exceptions.py +0 -0
  32. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/exceptions/security_exceptions.py +0 -0
  33. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/http/__init__.py +0 -0
  34. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/http/httpx_http_client.py +0 -0
  35. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/http/request_http_client.py +0 -0
  36. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/interfaces/__init__.py +0 -0
  37. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/interfaces/databus.py +0 -0
  38. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/interfaces/http.py +0 -0
  39. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/interfaces/keyvault.py +0 -0
  40. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/messaging/http_databus.py +0 -0
  41. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/messaging/nats_databus.py +0 -0
  42. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/metrics/__init__.py +0 -0
  43. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/metrics/status_tracker.py +0 -0
  44. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/models/__init__.py +0 -0
  45. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/security/__init__.py +0 -0
  46. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/security/key_vault/__init__.py +0 -0
  47. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/security/key_vault/aws_secret_manager.py +0 -0
  48. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/security/key_vault/azure_keyvault.py +0 -0
  49. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/tests/__init__.py +0 -0
  50. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/tests/config/__init__.py +0 -0
  51. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/tests/config/test_config.py +0 -0
  52. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/tests/logger/__init__.py +0 -0
  53. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/tests/logger/test_logger.py +0 -0
  54. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/tests/messaging/__init__.py +0 -0
  55. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/tests/messaging/test_nats_interface.py +0 -0
  56. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/tests/utils/__init__.py +0 -0
  57. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/tests/utils/test_data_validators.py +0 -0
  58. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/tests/utils/test_date_format_utils.py +0 -0
  59. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/tests/utils/test_string_utils.py +0 -0
  60. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/utils/__init__.py +0 -0
  61. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/utils/data_validators_utils.py +0 -0
  62. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/utils/date_format_utils.py +0 -0
  63. {fdc_shared_kernel-0.0.32 → fdc_shared_kernel-0.0.34}/shared_kernel/utils/string_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fdc_shared_kernel
3
- Version: 0.0.32
3
+ Version: 0.0.34
4
4
  Summary: Shared library for microservice
5
5
  Author-email: Shikhil S <shikhil.s@dbizsolution.com>, Ahammed Akdham N <ahammedakdham.n@dbizsolution.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fdc_shared_kernel
3
- Version: 0.0.32
3
+ Version: 0.0.34
4
4
  Summary: Shared library for microservice
5
5
  Author-email: Shikhil S <shikhil.s@dbizsolution.com>, Ahammed Akdham N <ahammedakdham.n@dbizsolution.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -34,6 +34,7 @@ shared_kernel/interfaces/http.py
34
34
  shared_kernel/interfaces/keyvault.py
35
35
  shared_kernel/logger/__init__.py
36
36
  shared_kernel/messaging/__init__.py
37
+ shared_kernel/messaging/event_bridge_sqs_databus.py
37
38
  shared_kernel/messaging/http_databus.py
38
39
  shared_kernel/messaging/nats_databus.py
39
40
  shared_kernel/metrics/__init__.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "fdc_shared_kernel"
7
- version = "0.0.32"
7
+ version = "0.0.34"
8
8
  requires-python = ">=3.7"
9
9
  readme = "README_pypi.md"
10
10
  description = "Shared library for microservice"
@@ -16,6 +16,8 @@ class JSONFormatter(logging.Formatter):
16
16
  "level": record.levelname,
17
17
  "message": record.getMessage(),
18
18
  }
19
+ if hasattr(record, 'extra_data'):
20
+ log_record.update(record.extra_data)
19
21
  if record.exc_info:
20
22
  log_record["exception"] = self.formatException(record.exc_info)
21
23
  return json.dumps(log_record)
@@ -67,7 +69,7 @@ class Logger:
67
69
  """
68
70
  stream_handler = logging.StreamHandler()
69
71
  stream_handler.setLevel(self.logger.level)
70
- stream_handler.setFormatter(self.formatter)
72
+ stream_handler.setFormatter(JSONFormatter())
71
73
  self.logger.addHandler(stream_handler)
72
74
 
73
75
  def add_file_handler(self, log_file, log_directory="./logs"):
@@ -93,13 +95,17 @@ class Logger:
93
95
  self.logger.addHandler(json_file_handler)
94
96
 
95
97
  def info(self, message, *args, **kwargs):
96
- self.logger.info(message, *args, **kwargs)
98
+ extra_data = {"extra_data": kwargs}
99
+ self.logger.info(message, *args, extra=extra_data)
97
100
 
98
101
  def error(self, message, *args, **kwargs):
99
- self.logger.error(message, *args, **kwargs)
102
+ extra_data = {"extra_data": kwargs}
103
+ self.logger.error(message, exc_info=True, *args, extra=extra_data)
100
104
 
101
105
  def debug(self, message, *args, **kwargs):
102
- self.logger.debug(message, *args, **kwargs)
106
+ extra_data = {"extra_data": kwargs}
107
+ self.logger.debug(message, *args, extra=extra_data)
103
108
 
104
109
  def warning(self, message, *args, **kwargs):
105
- self.logger.warning(message, *args, **kwargs)
110
+ extra_data = {"extra_data": kwargs}
111
+ self.logger.warning(message, *args, extra=extra_data)
@@ -1,10 +1,16 @@
1
1
  from shared_kernel.messaging.nats_databus import NATSDataBus
2
2
  from shared_kernel.messaging.http_databus import HTTPDataBus
3
+ from shared_kernel.messaging.event_bridge_sqs_databus import EventBridgeSQSDataBus
3
4
  from shared_kernel.interfaces import DataBus
4
5
 
5
6
 
7
+ # create an enum for the buses available
6
8
  class DataBus:
7
- data_bus_classes = {"NATS": NATSDataBus, "HTTP": HTTPDataBus}
9
+ data_bus_classes = {
10
+ "NATS": NATSDataBus,
11
+ "HTTP": HTTPDataBus,
12
+ "EventBridgeSQS": EventBridgeSQSDataBus,
13
+ }
8
14
 
9
15
  @staticmethod
10
16
  def create_data_bus(bus_type: str, config: dict) -> DataBus:
@@ -0,0 +1,162 @@
1
+ import json
2
+ import logging
3
+ import boto3
4
+ from botocore.exceptions import ClientError
5
+ from typing import Callable, Any, Dict
6
+ from concurrent.futures import ThreadPoolExecutor
7
+ import threading
8
+
9
+ logging.getLogger().setLevel(logging.INFO)
10
+
11
+ class EventBridgeSQSDataBus:
12
+ """
13
+ An EventBridge and SQS interface class to handle event-driven communication.
14
+ """
15
+ _instance = None
16
+
17
+ def __new__(cls, *args, **kwargs):
18
+ if cls._instance is None:
19
+ cls._instance = super(EventBridgeSQSDataBus, cls).__new__(cls)
20
+ return cls._instance
21
+
22
+ def __init__(self, config: Dict = None):
23
+ """
24
+ Initialize the EventBridgeSQSDataBus and start listening to the SQS queue.
25
+ Args:
26
+ config (Dict): A dictionary containing the EventBridge and SQS configuration.
27
+ """
28
+ if not hasattr(self, "initialized"): # Prevent reinitialization
29
+ super().__init__()
30
+ self.eventbridge = boto3.client('events')
31
+ self.sqs = boto3.client('sqs')
32
+ self.event_bus_name = config.get('event_bus_name')
33
+ self.queue_url = config.get('queue_url')
34
+ self.callback_registry = {} # Store callbacks for subscribed events
35
+ self.initialized = True
36
+ self.stop_event = threading.Event()
37
+
38
+ if self.queue_url:
39
+ # Start listening to the SQS queue as soon as initialized in a thread pool
40
+ self.executor = ThreadPoolExecutor(max_workers=4)
41
+ self.executor.submit(self._start_listening)
42
+
43
+ def subscribe_async_event(self, event_name: str, event_pattern: str, callback: Callable[[Any], None]):
44
+ """
45
+ Subscribe to an event by creating an EventBridge rule and store the callback for the event.
46
+ Args:
47
+ event_name (str): The name of the event to subscribe to.
48
+ event_pattern (str): The event pattern for filtering events.
49
+ callback (Callable[[Any], None]): The callback function to be invoked when the event is received.
50
+ """
51
+ rule_name = f'{event_name}_rule'
52
+ try:
53
+ # Create EventBridge Rule
54
+ self.eventbridge.put_rule(
55
+ Name=rule_name,
56
+ EventPattern=event_pattern,
57
+ State='ENABLED',
58
+ EventBusName=self.event_bus_name
59
+ )
60
+ logging.info(f"Event rule '{rule_name}' created.")
61
+
62
+ # Add SQS queue as target
63
+ self.eventbridge.put_targets(
64
+ Rule=rule_name,
65
+ EventBusName=self.event_bus_name,
66
+ Targets=[{
67
+ 'Id': f'{event_name}_sqs_target',
68
+ 'Arn': 'arn:aws:sqs:us-east-1:012765396827:test_fdc_queue', # SQS queue ARN
69
+ }]
70
+ )
71
+ logging.info(f"SQS queue target added to rule '{rule_name}'.")
72
+
73
+ # Register the callback for the event
74
+ self.callback_registry[event_name] = callback
75
+ logging.info(f"Callback registered for event '{event_name}'.")
76
+
77
+ except ClientError as e:
78
+ logging.error(f"Failed to subscribe to event '{event_name}': {e}")
79
+
80
+ def _start_listening(self):
81
+ """
82
+ Start listening to the SQS queue and process messages using the stored callbacks in a thread.
83
+ """
84
+ logging.info(f"Listening to SQS queue '{self.queue_url}' for messages...")
85
+
86
+ while not self.stop_event.is_set():
87
+ try:
88
+ # Poll SQS queue for messages
89
+ response = self.sqs.receive_message(
90
+ QueueUrl=self.queue_url,
91
+ MaxNumberOfMessages=10,
92
+ WaitTimeSeconds=20
93
+ )
94
+ messages = response.get('Messages', [])
95
+ for message in messages:
96
+ logging.info(f"Received message from SQS: {message}")
97
+ self._process_message(message)
98
+ # Delete the message from the queue after processing
99
+ # self.delete_message(message['ReceiptHandle'])
100
+ except ClientError as e:
101
+ logging.error(f"Error receiving message from SQS: {e}")
102
+
103
+ def _process_message(self, message: Dict):
104
+ """
105
+ Process an incoming message and invoke the registered callback for the event.
106
+ Args:
107
+ message (Dict): The message received from the SQS queue.
108
+ """
109
+ try:
110
+ body = json.loads(message['Body'])
111
+ event_name = body.get('detail-type')
112
+ event_detail = json.loads(body.get('detail', {}))
113
+
114
+ # Check if a callback is registered for the event
115
+ if event_name in self.callback_registry:
116
+ callback = self.callback_registry[event_name]
117
+ logging.info(f"Invoking callback for event '{event_name}' with payload: {event_detail}")
118
+ callback(event_detail)
119
+ else:
120
+ logging.warning(f"No callback registered for event '{event_name}'.")
121
+ except Exception as e:
122
+ logging.error(f"Error processing message: {e}")
123
+
124
+ def publish_event(self, event_name: str, event_payload: dict):
125
+ """
126
+ Publish an event to the EventBridge.
127
+ Args:
128
+ event_name (str): The name of the event to publish.
129
+ event_payload (dict): The payload of the event.
130
+ Returns:
131
+ bool: True if the event was published successfully.
132
+ """
133
+ try:
134
+ response = self.eventbridge.put_events(
135
+ Entries=[{
136
+ 'Source': 'my.application',
137
+ 'DetailType': event_name,
138
+ 'Detail': json.dumps(event_payload),
139
+ 'EventBusName': self.event_bus_name,
140
+ }]
141
+ )
142
+ logging.info(f"Published event '{event_name}': {event_payload}, response: {response}")
143
+ return True
144
+ except ClientError as e:
145
+ logging.error(f"Failed to publish event: {e}")
146
+ return False
147
+
148
+ def delete_message(self, receipt_handle: str):
149
+ """
150
+ Delete a message from the SQS queue.
151
+ Args:
152
+ receipt_handle (str): The receipt handle associated with the message to delete.
153
+ """
154
+ try:
155
+ self.sqs.delete_message(
156
+ QueueUrl=self.queue_url,
157
+ ReceiptHandle=receipt_handle
158
+ )
159
+ logging.info(f"Message deleted from SQS queue with receipt handle '{receipt_handle}'.")
160
+ except ClientError as e:
161
+ logging.error(f"Failed to delete message from SQS: {e}")
162
+