dnaStreaming 2.1.0__tar.gz → 2.2.1__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 (28) hide show
  1. {dnastreaming-2.1.0/dnaStreaming.egg-info → dnastreaming-2.2.1}/PKG-INFO +2 -2
  2. dnastreaming-2.2.1/dnaStreaming/demo/show_ha_stream_async.py +36 -0
  3. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming/listener.py +68 -1
  4. dnastreaming-2.2.1/dnaStreaming/services/availability_service.py +87 -0
  5. dnastreaming-2.2.1/dnaStreaming/services/pubsub_service.py +19 -0
  6. {dnastreaming-2.1.0 → dnastreaming-2.2.1/dnaStreaming.egg-info}/PKG-INFO +2 -2
  7. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming.egg-info/SOURCES.txt +2 -0
  8. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/setup.py +1 -1
  9. dnastreaming-2.1.0/dnaStreaming/services/pubsub_service.py +0 -13
  10. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/LICENSE +0 -0
  11. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/MANIFEST.in +0 -0
  12. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/README.rst +0 -0
  13. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming/__init__.py +0 -0
  14. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming/config.py +0 -0
  15. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming/customer_config.json +0 -0
  16. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming/demo/__init__.py +0 -0
  17. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming/demo/pubsub_stream.py +0 -0
  18. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming/demo/show_stream.py +0 -0
  19. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming/demo/show_stream_async.py +0 -0
  20. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming/services/__init__.py +0 -0
  21. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming/services/authentication_service.py +0 -0
  22. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming/services/credentials_service.py +0 -0
  23. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming/test/__init__.py +0 -0
  24. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming/test/test_config.py +0 -0
  25. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming.egg-info/dependency_links.txt +0 -0
  26. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming.egg-info/requires.txt +0 -0
  27. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/dnaStreaming.egg-info/top_level.txt +0 -0
  28. {dnastreaming-2.1.0 → dnastreaming-2.2.1}/setup.cfg +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dnaStreaming
3
- Version: 2.1.0
3
+ Version: 2.2.1
4
4
  Summary: Dow Jones DNA Streaming Project
5
5
  Home-page: https://github.com/dowjones/dj-dna-streams-python
6
- Download-URL: https://github.com/dowjones/dj-dna-streams-python/archive/release-2.1.0.tar.gz
6
+ Download-URL: https://github.com/dowjones/dj-dna-streams-python/archive/release-2.2.1.tar.gz
7
7
  Author: Zachary Kagan
8
8
  Author-email: zachary.kagan@dowjones.com
9
9
  License: MIT
@@ -0,0 +1,36 @@
1
+ import os
2
+ from time import sleep
3
+ from dnaStreaming.listener import Listener
4
+
5
+ listener = Listener()
6
+ quiet_demo = os.getenv('QUIET_DEMO', "false") == "true"
7
+ max_secs = 1000
8
+ print("\n[ACTIVITY] Receiving messages (ASYNC) for {} seconds...\n[0]".format(max_secs), end='')
9
+
10
+
11
+ def callback(message, subscription_id):
12
+ callback.counter += 1
13
+ if not quiet_demo:
14
+ if message['action'] != 'del':
15
+ print('[INFO] [SUBSCRIPTION]: {} [MSG] [{}]: AN: {}, TITLE: {}'.format(subscription_id, callback.counter, message['an'], message['title']))
16
+ else:
17
+ print('[INFO] [SUBSCRIPTION]: {} [MSG] [{}]: AN: {}, *** DELETE ***'.format(subscription_id, callback.counter, message['an']))
18
+ else:
19
+ if callback.counter % 10 == 0:
20
+ print('[{}]'.format(callback.counter), end='')
21
+ else:
22
+ print('.', end='')
23
+ return True
24
+
25
+
26
+ callback.counter = 0
27
+ listener_controller = listener.listen_async_ha(callback)
28
+
29
+ # Stop receiving messages after 5 seconds
30
+ for count in range(0, max_secs):
31
+ sleep(1)
32
+
33
+ if listener_controller.listener_is_running():
34
+ listener_controller.stop_listener()
35
+
36
+ print("stop receiving messages")
@@ -1,7 +1,7 @@
1
1
  import time
2
2
  import requests
3
3
  import json
4
- from threading import Thread
4
+ from threading import Thread, Event
5
5
 
6
6
  from google.api_core.exceptions import GoogleAPICallError, NotFound
7
7
  from google import pubsub_v1
@@ -9,7 +9,19 @@ from google import pubsub_v1
9
9
  from dnaStreaming import logger
10
10
  from dnaStreaming.config import Config
11
11
  from dnaStreaming.services import pubsub_service, credentials_service
12
+ from dnaStreaming.services.availability_service import MAIN_REGION, BACKUP_REGION, ha_listen
12
13
 
14
+ class ListenerController(object):
15
+ def __init__(self, thread, stop_event):
16
+ self.thread = thread
17
+ self.stop_event = stop_event
18
+
19
+ def stop_listener(self):
20
+ self.stop_event.set()
21
+ self.thread.join()
22
+
23
+ def listener_is_running(self):
24
+ self.thread.is_alive()
13
25
 
14
26
  class Listener(object):
15
27
  DEFAULT_UNLIMITED_MESSAGES = None
@@ -112,3 +124,58 @@ class Listener(object):
112
124
  logger.info(
113
125
  'Listeners for subscriptions have been configured, set and await message arrival.')
114
126
  return subscription
127
+
128
+ def listen_async_ha(self, on_message_callback):
129
+ def ack_message_and_callback(message, subscription_path):
130
+ pubsub_msg = json.loads(message.data)
131
+ logger.info("Received news message with ID: {}".format(
132
+ pubsub_msg['data'][0]['id']))
133
+ news_msg = pubsub_msg['data'][0]['attributes']
134
+ short_subscription_id = subscription_path.split("/")[-1]
135
+ on_message_callback(news_msg, short_subscription_id)
136
+ message.ack()
137
+
138
+ main_pubsub_client = pubsub_service.get_client(self.config, MAIN_REGION)
139
+ backup_pubsub_client = pubsub_service.get_client(self.config, BACKUP_REGION)
140
+
141
+ subscription_id = self.config.subscription()
142
+
143
+ if not subscription_id:
144
+ raise Exception(
145
+ 'No subscription specified. You must specify the subscription ID either through an environment variable, a config file or '
146
+ 'by passing the value to the method.')
147
+
148
+ streaming_credentials = credentials_service.fetch_credentials(
149
+ self.config)
150
+
151
+ api_host = self.config.get_uri_context()
152
+ user_key = self.config.get_user_key()
153
+
154
+ main_subscription_id = subscription_id if "-bak-" not in subscription_id else subscription_id.replace("-filtered-bak-", "-filtered-")
155
+ backup_subscription_id = subscription_id if "-bak-" in subscription_id else subscription_id.replace("-filtered-", "-filtered-bak-")
156
+
157
+ main_subscription_path = main_pubsub_client.subscription_path(
158
+ streaming_credentials['project_id'], main_subscription_id)
159
+ backup_subscription_path = backup_pubsub_client.subscription_path(
160
+ streaming_credentials['project_id'], backup_subscription_id)
161
+
162
+ stop_event = Event()
163
+ listener_thread = Thread(target=ha_listen, daemon=True, args=(
164
+ api_host,
165
+ user_key,
166
+ subscription_id,
167
+ stop_event,
168
+ main_subscription_path,
169
+ backup_subscription_path,
170
+ main_pubsub_client,
171
+ backup_pubsub_client,
172
+ ack_message_and_callback
173
+ ))
174
+ listener_thread.start()
175
+
176
+ listener_controller = ListenerController(listener_thread, stop_event)
177
+
178
+ logger.info(
179
+ 'Listeners for subscriptions have been configured, set and await message arrival.')
180
+
181
+ return listener_controller
@@ -0,0 +1,87 @@
1
+ import requests
2
+ import time
3
+
4
+ from dnaStreaming import logger
5
+
6
+ MAIN_REGION = "us-central1"
7
+ BACKUP_REGION = "us-east5"
8
+ COOLDOWN_PERIOD = 5 * 60
9
+
10
+ def get_active_region(api_host, subscription_id, user_key):
11
+
12
+ try:
13
+ ha_status_url = f"{api_host}/stream_health/get_active_region"
14
+
15
+ headers = {
16
+ "subscription-id": subscription_id,
17
+ "user-key": user_key
18
+ }
19
+
20
+ response = requests.get(url=ha_status_url, headers=headers)
21
+
22
+ assert response.status_code == 200, "Failed to fetch active region"
23
+
24
+ payload = response.json()
25
+
26
+ active_region = payload["data"]["active_region"]
27
+
28
+ return active_region
29
+
30
+ except:
31
+
32
+ return None
33
+
34
+
35
+ def ha_listen(api_host, user_key, subscription_id, stop_event, main_subscription_path, backup_subscription_path, main_pubsub_client, backup_pubsub_client, callback):
36
+
37
+ # The listener starts reading messages from the main region by default.
38
+
39
+ current_region = MAIN_REGION
40
+
41
+ def wrapped_callback(subscription_path):
42
+ def inner_callback(message):
43
+ callback(message, subscription_path)
44
+
45
+ return inner_callback
46
+
47
+ streaming_pull_future = main_pubsub_client.subscribe(
48
+ main_subscription_path, callback=wrapped_callback(main_subscription_path))
49
+
50
+ while not stop_event.is_set():
51
+
52
+ active_region = get_active_region(api_host, subscription_id, user_key)
53
+
54
+ if active_region is None or active_region not in (MAIN_REGION, BACKUP_REGION):
55
+ logger.warning(f"Got invalid region from API: {active_region}. Listener will keep reading from region {current_region}")
56
+ continue
57
+
58
+ if current_region != active_region:
59
+
60
+ logger.warning(f"Switch event detected in, switching from region {current_region} to region {active_region}")
61
+
62
+ logger.warning(f"Stopping listener in region {current_region}...")
63
+
64
+ # We stop the previous listening process
65
+ streaming_pull_future.cancel()
66
+ streaming_pull_future.result()
67
+
68
+ logger.warning(f"Stopped listener in region {current_region}")
69
+
70
+ logger.warning(f"Starting listener in region {active_region}...")
71
+
72
+ if active_region == MAIN_REGION:
73
+ streaming_pull_future = main_pubsub_client.subscribe(
74
+ main_subscription_path, callback=wrapped_callback(main_subscription_path))
75
+ else: # active_region == BACKUP_REGION
76
+ streaming_pull_future = backup_pubsub_client.subscribe(
77
+ backup_subscription_path, callback=wrapped_callback(backup_subscription_path))
78
+
79
+ logger.warning(f"Started listener in region {active_region}")
80
+
81
+ current_region = active_region
82
+
83
+ # We wait 5 minutes for cooldown for next call to API
84
+ time.sleep(COOLDOWN_PERIOD)
85
+
86
+ streaming_pull_future.cancel()
87
+ streaming_pull_future.result()
@@ -0,0 +1,19 @@
1
+ from __future__ import absolute_import, division, print_function
2
+
3
+ from google.cloud.pubsub_v1 import SubscriberClient
4
+
5
+ from dnaStreaming.services import authentication_service
6
+ from dnaStreaming.services import credentials_service
7
+ from dnaStreaming.services.availability_service import MAIN_REGION, BACKUP_REGION
8
+
9
+
10
+ def get_client(config, region=None):
11
+ streaming_credentials = credentials_service.fetch_credentials(config)
12
+ credentials = authentication_service.get_authenticated_oauth_credentials(streaming_credentials)
13
+
14
+ if region in (MAIN_REGION, BACKUP_REGION):
15
+ client_options = {"api_endpoint": f"{region}-pubsub.googleapis.com:443"}
16
+ else:
17
+ client_options = {"api_endpoint": "pubsub.googleapis.com:443"}
18
+
19
+ return SubscriberClient(credentials=credentials, client_options=client_options)
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dnaStreaming
3
- Version: 2.1.0
3
+ Version: 2.2.1
4
4
  Summary: Dow Jones DNA Streaming Project
5
5
  Home-page: https://github.com/dowjones/dj-dna-streams-python
6
- Download-URL: https://github.com/dowjones/dj-dna-streams-python/archive/release-2.1.0.tar.gz
6
+ Download-URL: https://github.com/dowjones/dj-dna-streams-python/archive/release-2.2.1.tar.gz
7
7
  Author: Zachary Kagan
8
8
  Author-email: zachary.kagan@dowjones.com
9
9
  License: MIT
@@ -14,10 +14,12 @@ dnaStreaming.egg-info/requires.txt
14
14
  dnaStreaming.egg-info/top_level.txt
15
15
  dnaStreaming/demo/__init__.py
16
16
  dnaStreaming/demo/pubsub_stream.py
17
+ dnaStreaming/demo/show_ha_stream_async.py
17
18
  dnaStreaming/demo/show_stream.py
18
19
  dnaStreaming/demo/show_stream_async.py
19
20
  dnaStreaming/services/__init__.py
20
21
  dnaStreaming/services/authentication_service.py
22
+ dnaStreaming/services/availability_service.py
21
23
  dnaStreaming/services/credentials_service.py
22
24
  dnaStreaming/services/pubsub_service.py
23
25
  dnaStreaming/test/__init__.py
@@ -6,7 +6,7 @@ this_directory = path.abspath(path.dirname(__file__))
6
6
  with open(path.join(this_directory, 'README.rst'), encoding='utf-8') as f:
7
7
  long_description = f.read()
8
8
 
9
- VERSION = "2.1.0"
9
+ VERSION = "2.2.1"
10
10
  RELEASE_TAG = f"release-{VERSION}"
11
11
 
12
12
  setup(
@@ -1,13 +0,0 @@
1
- from __future__ import absolute_import, division, print_function
2
-
3
- from google.cloud.pubsub_v1 import SubscriberClient
4
-
5
- from dnaStreaming.services import authentication_service
6
- from dnaStreaming.services import credentials_service
7
-
8
-
9
- def get_client(config):
10
- streaming_credentials = credentials_service.fetch_credentials(config)
11
- credentials = authentication_service.get_authenticated_oauth_credentials(streaming_credentials)
12
-
13
- return SubscriberClient(credentials=credentials)
File without changes
File without changes
File without changes
File without changes