Skip to content
This repository was archived by the owner on Oct 12, 2023. It is now read-only.

Commit 97137ac

Browse files
authored
Merge pull request #51 from annatisch/eh_scenarios
EPH improvements
2 parents dd38016 + 0c27572 commit 97137ac

16 files changed

+216
-61
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,5 @@ ENV/
110110
azure/mgmt/
111111
azure/common/
112112
azure/profiles/
113+
azure/servicebus/
113114
features/steps/mgmt_settings_real.py

HISTORY.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,22 @@
33
Release History
44
===============
55

6+
0.2.0 (2018-08-06)
7+
++++++++++++++++++
8+
9+
- Stability improvements for EPH.
10+
- Updated uAMQP version.
11+
- Added new configuration options for Sender and Receiver; `keep_alive` and `auto_reconnect`.
12+
These flags have been added to the following:
13+
14+
- `EventHubClient.add_receiver`
15+
- `EventHubClient.add_sender`
16+
- `EventHubClientAsync.add_async_receiver`
17+
- `EventHubClientAsync.add_async_sender`
18+
- `EPHOptions.keey_alive_interval`
19+
- `EPHOptions.auto_reconnect_on_error`
20+
21+
622
0.2.0rc2 (2018-07-29)
723
+++++++++++++++++++++
824

azure/eventhub/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Licensed under the MIT License. See License.txt in the project root for license information.
44
# --------------------------------------------------------------------------------------------
55

6-
__version__ = "0.2.0rc2"
6+
__version__ = "0.2.0"
77

88
from azure.eventhub.common import EventData, EventHubError, Offset
99
from azure.eventhub.client import EventHubClient

azure/eventhub/_async/__init__.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ async def _start_client_async(self, client):
7777
try:
7878
await client.open_async()
7979
except Exception as exp: # pylint: disable=broad-except
80+
log.info("Encountered error while starting handler: {}".format(exp))
8081
await client.close_async(exception=exp)
8182

8283
async def _handle_redirect(self, redirects):
@@ -164,7 +165,9 @@ async def get_eventhub_info_async(self):
164165
finally:
165166
await mgmt_client.close_async()
166167

167-
def add_async_receiver(self, consumer_group, partition, offset=None, prefetch=300, operation=None, loop=None):
168+
def add_async_receiver(
169+
self, consumer_group, partition, offset=None, prefetch=300,
170+
operation=None, keep_alive=30, auto_reconnect=True, loop=None):
168171
"""
169172
Add an async receiver to the client for a particular consumer group and partition.
170173
@@ -184,11 +187,15 @@ def add_async_receiver(self, consumer_group, partition, offset=None, prefetch=30
184187
path = self.address.path + operation if operation else self.address.path
185188
source_url = "amqps://{}{}/ConsumerGroups/{}/Partitions/{}".format(
186189
self.address.hostname, path, consumer_group, partition)
187-
handler = AsyncReceiver(self, source_url, offset=offset, prefetch=prefetch, loop=loop)
190+
handler = AsyncReceiver(
191+
self, source_url, offset=offset, prefetch=prefetch,
192+
keep_alive=keep_alive, auto_reconnect=auto_reconnect, loop=loop)
188193
self.clients.append(handler)
189194
return handler
190195

191-
def add_async_epoch_receiver(self, consumer_group, partition, epoch, prefetch=300, operation=None, loop=None):
196+
def add_async_epoch_receiver(
197+
self, consumer_group, partition, epoch, prefetch=300,
198+
operation=None, keep_alive=30, auto_reconnect=True, loop=None):
192199
"""
193200
Add an async receiver to the client with an epoch value. Only a single epoch receiver
194201
can connect to a partition at any given time - additional epoch receivers must have
@@ -211,11 +218,13 @@ def add_async_epoch_receiver(self, consumer_group, partition, epoch, prefetch=30
211218
path = self.address.path + operation if operation else self.address.path
212219
source_url = "amqps://{}{}/ConsumerGroups/{}/Partitions/{}".format(
213220
self.address.hostname, path, consumer_group, partition)
214-
handler = AsyncReceiver(self, source_url, prefetch=prefetch, epoch=epoch, loop=loop)
221+
handler = AsyncReceiver(
222+
self, source_url, prefetch=prefetch, epoch=epoch,
223+
keep_alive=keep_alive, auto_reconnect=auto_reconnect, loop=loop)
215224
self.clients.append(handler)
216225
return handler
217226

218-
def add_async_sender(self, partition=None, operation=None, loop=None):
227+
def add_async_sender(self, partition=None, operation=None, keep_alive=30, auto_reconnect=True, loop=None):
219228
"""
220229
Add an async sender to the client to send ~azure.eventhub.common.EventData object
221230
to an EventHub.
@@ -232,6 +241,8 @@ def add_async_sender(self, partition=None, operation=None, loop=None):
232241
target = "amqps://{}{}".format(self.address.hostname, self.address.path)
233242
if operation:
234243
target = target + operation
235-
handler = AsyncSender(self, target, partition=partition, loop=loop)
244+
handler = AsyncSender(
245+
self, target, partition=partition, keep_alive=keep_alive,
246+
auto_reconnect=auto_reconnect, loop=loop)
236247
self.clients.append(handler)
237248
return handler

azure/eventhub/_async/receiver_async.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
# --------------------------------------------------------------------------------------------
55

66
import asyncio
7+
import uuid
8+
import logging
79

810
from uamqp import errors, types
911
from uamqp import ReceiveClientAsync, Source
@@ -12,13 +14,17 @@
1214
from azure.eventhub.receiver import Receiver
1315
from azure.eventhub.common import _error_handler
1416

17+
log = logging.getLogger(__name__)
18+
1519

1620
class AsyncReceiver(Receiver):
1721
"""
1822
Implements the async API of a Receiver.
1923
"""
2024

21-
def __init__(self, client, source, offset=None, prefetch=300, epoch=None, loop=None): # pylint: disable=super-init-not-called
25+
def __init__( # pylint: disable=super-init-not-called
26+
self, client, source, offset=None, prefetch=300, epoch=None,
27+
keep_alive=None, auto_reconnect=True, loop=None):
2228
"""
2329
Instantiate an async receiver.
2430
@@ -39,10 +45,14 @@ def __init__(self, client, source, offset=None, prefetch=300, epoch=None, loop=N
3945
self.offset = offset
4046
self.prefetch = prefetch
4147
self.epoch = epoch
48+
self.keep_alive = keep_alive
49+
self.auto_reconnect = auto_reconnect
4250
self.retry_policy = errors.ErrorPolicy(max_retries=3, on_error=_error_handler)
4351
self.redirected = None
4452
self.error = None
4553
self.properties = None
54+
partition = self.source.split('/')[-1]
55+
self.name = "EHReceiver-{}-partition{}".format(uuid.uuid4(), partition)
4656
source = Source(self.source)
4757
if self.offset is not None:
4858
source.set_filter(self.offset.selector())
@@ -56,7 +66,9 @@ def __init__(self, client, source, offset=None, prefetch=300, epoch=None, loop=N
5666
link_properties=self.properties,
5767
timeout=self.timeout,
5868
error_policy=self.retry_policy,
59-
keep_alive_interval=30,
69+
keep_alive_interval=self.keep_alive,
70+
client_name=self.name,
71+
properties=self.client.create_properties(),
6072
loop=self.loop)
6173

6274
async def open_async(self):
@@ -85,7 +97,9 @@ async def open_async(self):
8597
link_properties=self.properties,
8698
timeout=self.timeout,
8799
error_policy=self.retry_policy,
88-
keep_alive_interval=30,
100+
keep_alive_interval=self.keep_alive,
101+
client_name=self.name,
102+
properties=self.client.create_properties(),
89103
loop=self.loop)
90104
await self._handler.open_async()
91105
while not await self.has_started():
@@ -110,7 +124,8 @@ async def reconnect_async(self):
110124
link_properties=self.properties,
111125
timeout=self.timeout,
112126
error_policy=self.retry_policy,
113-
keep_alive_interval=30,
127+
keep_alive_interval=self.keep_alive,
128+
client_name=self.name,
114129
properties=self.client.create_properties(),
115130
loop=self.loop)
116131
await self._handler.open_async()
@@ -189,17 +204,27 @@ async def receive(self, max_batch_size=None, timeout=None):
189204
data_batch.append(event_data)
190205
return data_batch
191206
except (errors.LinkDetach, errors.ConnectionClose) as shutdown:
192-
if shutdown.action.retry:
207+
if shutdown.action.retry and self.auto_reconnect:
208+
log.info("AsyncReceiver detached. Attempting reconnect.")
193209
await self.reconnect_async()
194210
return data_batch
195211
else:
212+
log.info("AsyncReceiver detached. Shutting down.")
213+
error = EventHubError(str(shutdown), shutdown)
214+
await self.close_async(exception=error)
215+
raise error
216+
except errors.MessageHandlerError as shutdown:
217+
if self.auto_reconnect:
218+
log.info("AsyncReceiver detached. Attempting reconnect.")
219+
await self.reconnect_async()
220+
return data_batch
221+
else:
222+
log.info("AsyncReceiver detached. Shutting down.")
196223
error = EventHubError(str(shutdown), shutdown)
197224
await self.close_async(exception=error)
198225
raise error
199-
except errors.MessageHandlerError:
200-
await self.reconnect_async()
201-
return data_batch
202226
except Exception as e:
227+
log.info("Unexpected error occurred ({}). Shutting down.".format(e))
203228
error = EventHubError("Receive failed: {}".format(e))
204229
await self.close_async(exception=error)
205230
raise error

azure/eventhub/_async/sender_async.py

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Licensed under the MIT License. See License.txt in the project root for license information.
44
# --------------------------------------------------------------------------------------------
55

6+
import uuid
67
import asyncio
78

89
from uamqp import constants, errors
@@ -17,7 +18,7 @@ class AsyncSender(Sender):
1718
Implements the async API of a Sender.
1819
"""
1920

20-
def __init__(self, client, target, partition=None, loop=None): # pylint: disable=super-init-not-called
21+
def __init__(self, client, target, partition=None, keep_alive=None, auto_reconnect=True, loop=None): # pylint: disable=super-init-not-called
2122
"""
2223
Instantiate an EventHub event SenderAsync handler.
2324
@@ -31,18 +32,23 @@ def __init__(self, client, target, partition=None, loop=None): # pylint: disabl
3132
self.client = client
3233
self.target = target
3334
self.partition = partition
35+
self.keep_alive = keep_alive
36+
self.auto_reconnect = auto_reconnect
3437
self.retry_policy = errors.ErrorPolicy(max_retries=3, on_error=_error_handler)
38+
self.name = "EHSender-{}".format(uuid.uuid4())
3539
self.redirected = None
3640
self.error = None
3741
if partition:
3842
self.target += "/Partitions/" + partition
43+
self.name += "-partition{}".format(partition)
3944
self._handler = SendClientAsync(
4045
self.target,
4146
auth=self.client.get_auth(),
4247
debug=self.client.debug,
4348
msg_timeout=Sender.TIMEOUT,
4449
error_policy=self.retry_policy,
45-
keep_alive_interval=30,
50+
keep_alive_interval=self.keep_alive,
51+
client_name=self.name,
4652
properties=self.client.create_properties(),
4753
loop=self.loop)
4854
self._outcome = None
@@ -65,7 +71,8 @@ async def open_async(self):
6571
debug=self.client.debug,
6672
msg_timeout=Sender.TIMEOUT,
6773
error_policy=self.retry_policy,
68-
keep_alive_interval=30,
74+
keep_alive_interval=self.keep_alive,
75+
client_name=self.name,
6976
properties=self.client.create_properties(),
7077
loop=self.loop)
7178
await self._handler.open_async()
@@ -85,7 +92,8 @@ async def reconnect_async(self):
8592
debug=self.client.debug,
8693
msg_timeout=Sender.TIMEOUT,
8794
error_policy=self.retry_policy,
88-
keep_alive_interval=30,
95+
keep_alive_interval=self.keep_alive,
96+
client_name=self.name,
8997
properties=self.client.create_properties(),
9098
loop=self.loop)
9199
await self._handler.open_async()
@@ -158,14 +166,19 @@ async def send(self, event_data):
158166
if self._outcome != constants.MessageSendResult.Ok:
159167
raise Sender._error(self._outcome, self._condition)
160168
except (errors.LinkDetach, errors.ConnectionClose) as shutdown:
161-
if shutdown.action.retry:
169+
if shutdown.action.retry and self.auto_reconnect:
170+
await self.reconnect_async()
171+
else:
172+
error = EventHubError(str(shutdown), shutdown)
173+
await self.close_async(exception=error)
174+
raise error
175+
except errors.MessageHandlerError as shutdown:
176+
if self.auto_reconnect:
162177
await self.reconnect_async()
163178
else:
164179
error = EventHubError(str(shutdown), shutdown)
165180
await self.close_async(exception=error)
166181
raise error
167-
except errors.MessageHandlerError:
168-
await self.reconnect_async()
169182
except Exception as e:
170183
error = EventHubError("Send failed: {}".format(e))
171184
await self.close_async(exception=error)
@@ -182,13 +195,18 @@ async def wait_async(self):
182195
try:
183196
await self._handler.wait_async()
184197
except (errors.LinkDetach, errors.ConnectionClose) as shutdown:
185-
if shutdown.action.retry:
198+
if shutdown.action.retry and self.auto_reconnect:
199+
await self.reconnect_async()
200+
else:
201+
error = EventHubError(str(shutdown), shutdown)
202+
await self.close_async(exception=error)
203+
raise error
204+
except errors.MessageHandlerError as shutdown:
205+
if self.auto_reconnect:
186206
await self.reconnect_async()
187207
else:
188208
error = EventHubError(str(shutdown), shutdown)
189209
await self.close_async(exception=error)
190210
raise error
191-
except errors.MessageHandlerError:
192-
await self.reconnect_async()
193211
except Exception as e:
194212
raise EventHubError("Send failed: {}".format(e))

azure/eventhub/client.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,9 @@ def get_eventhub_info(self):
303303
finally:
304304
mgmt_client.close()
305305

306-
def add_receiver(self, consumer_group, partition, offset=None, prefetch=300, operation=None):
306+
def add_receiver(
307+
self, consumer_group, partition, offset=None, prefetch=300,
308+
operation=None, keep_alive=30, auto_reconnect=True):
307309
"""
308310
Add a receiver to the client for a particular consumer group and partition.
309311
@@ -323,11 +325,15 @@ def add_receiver(self, consumer_group, partition, offset=None, prefetch=300, ope
323325
path = self.address.path + operation if operation else self.address.path
324326
source_url = "amqps://{}{}/ConsumerGroups/{}/Partitions/{}".format(
325327
self.address.hostname, path, consumer_group, partition)
326-
handler = Receiver(self, source_url, offset=offset, prefetch=prefetch)
328+
handler = Receiver(
329+
self, source_url, offset=offset, prefetch=prefetch,
330+
keep_alive=keep_alive, auto_reconnect=auto_reconnect)
327331
self.clients.append(handler)
328332
return handler
329333

330-
def add_epoch_receiver(self, consumer_group, partition, epoch, prefetch=300, operation=None):
334+
def add_epoch_receiver(
335+
self, consumer_group, partition, epoch, prefetch=300,
336+
operation=None, keep_alive=30, auto_reconnect=True):
331337
"""
332338
Add a receiver to the client with an epoch value. Only a single epoch receiver
333339
can connect to a partition at any given time - additional epoch receivers must have
@@ -350,11 +356,13 @@ def add_epoch_receiver(self, consumer_group, partition, epoch, prefetch=300, ope
350356
path = self.address.path + operation if operation else self.address.path
351357
source_url = "amqps://{}{}/ConsumerGroups/{}/Partitions/{}".format(
352358
self.address.hostname, path, consumer_group, partition)
353-
handler = Receiver(self, source_url, prefetch=prefetch, epoch=epoch)
359+
handler = Receiver(
360+
self, source_url, prefetch=prefetch, epoch=epoch,
361+
keep_alive=keep_alive, auto_reconnect=auto_reconnect)
354362
self.clients.append(handler)
355363
return handler
356364

357-
def add_sender(self, partition=None, operation=None):
365+
def add_sender(self, partition=None, operation=None, keep_alive=30, auto_reconnect=True):
358366
"""
359367
Add a sender to the client to send ~azure.eventhub.common.EventData object
360368
to an EventHub.
@@ -371,6 +379,6 @@ def add_sender(self, partition=None, operation=None):
371379
target = "amqps://{}{}".format(self.address.hostname, self.address.path)
372380
if operation:
373381
target = target + operation
374-
handler = Sender(self, target, partition=partition)
382+
handler = Sender(self, target, partition=partition, keep_alive=keep_alive, auto_reconnect=auto_reconnect)
375383
self.clients.append(handler)
376384
return handler

0 commit comments

Comments
 (0)