File: migration_guide.md

package info (click to toggle)
python-azure 20201208%2Bgit-6
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,437,920 kB
  • sloc: python: 4,287,452; javascript: 269; makefile: 198; sh: 187; xml: 106
file content (250 lines) | stat: -rw-r--r-- 21,824 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# Guide to migrate from azure-servicebus v0.50 to v7

This document is intended for users that are familiar with v0.50 of the Python SDK for Service Bus library (`azure-servicebus 0.50.x`) and wish 
to migrate their application to v7 of the same library.

For users new to the Python SDK for Service Bus, please see the [readme file for the azure-servicebus](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/servicebus/azure-servicebus/README.md).

## General changes
Version 7 of the azure-servicebus package is the result of our efforts to create a client library that is user-friendly and idiomatic to the Python ecosystem.
Alongside an API redesign driven by the new [Azure SDK Design Guidelines for Python](https://azure.github.io/azure-sdk/python_introduction.html#design-principles), 
the latest version improves on several areas from v0.50.

Note: The large version gap is in order to normalize service bus SDK versions across our languages, as they consolidate on structure as well.

### Specific clients for sending and receiving
In v7 we've simplified the API surface, making two distinct clients, rather than one for each of queue, topic, and subscription:
* `ServiceBusSender` for sending messages. [Sync API](https://azuresdkdocs.blob.core.windows.net/$web/python/azure-servicebus/latest/azure.servicebus.html#azure.servicebus.ServiceBusSender)
and [Async API](https://azuresdkdocs.blob.core.windows.net/$web/python/azure-servicebus/latest/azure.servicebus.aio.html#azure.servicebus.aio.ServiceBusSender)
* `ServiceBusReceiver` for receiving messages. [Sync API](https://azuresdkdocs.blob.core.windows.net/$web/python/azure-servicebus/latest/azure.servicebus.html#azure.servicebus.ServiceBusReceiver)
and [Async API](https://azuresdkdocs.blob.core.windows.net/$web/python/azure-servicebus/latest/azure.servicebus.aio.html#azure.servicebus.aio.ServiceBusReceiver)

As a user this will be largely transparent to you, as initialization will still occur primarily via the top level ServiceBusClient,
the primary difference will be that rather than creating a queue_client, for instance, and then a sender off of that, you would simply
create a servicebus queue sender off of your ServiceBusClient instance via the "get_queue_sender" method.

It should also be noted that many of the helper methods that previously existed on the intermediary client (e.g. QueueClient and `peek()`) now
exist on the receiver (in the case of `peek_messages()`) or sender itself.  This is to better consolidate functionality and align messaging link lifetime
semantics with the sender or receiver lifetime.

### Client constructors

| In v0.50 | Equivalent in v7 | Sample |
|---|---|---|
| `ServiceBusClient.from_connection_string()`    | `ServiceBusClient.from_connection_string()` | [using credential](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/servicebus/azure-servicebus/samples/sync_samples/authenticate_client_connstr.py ) |
| `QueueClient.from_connection_string()`    | `ServiceBusClient.from_connection_string().get_queue_<sender/receiver>()` | [client initialization](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/servicebus/azure-servicebus/samples/sync_samples/send_queue.py ) |
| `QueueClient.from_connection_string(idle_timeout=None)` | `ServiceBusClient.from_connection_string.get_queue_receiver(max_wait_time=None)` | [providing a timeout](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/servicebus/azure-servicebus/samples/sync_samples/session_pool_receive.py) |

### Sub-client initialization

In v0.50, to send or receive messages, a `QueueClient` would be created directly or from the `ServiceBusClient.get_queue` method,
after which user would call `get_sender` or `get_receiver` methods. Alternatively, `azure.servicebus.send_handler.Sender` and `azure.servicebus.receive_handler.Receiver` were used.

In v7.0, these are migrated to `ServiceBusSender` and `ServiceBusReceiver`. Note that these are internal sub-clients and should be initialized from the root `ServiceBusClient` as follows.

```Python
with ServiceBusClient.from_connection_string(connstr) as client:
    with client.get_queue_sender(queue_name) as sender:
        # Sending a single message
        single_message = ServiceBusMessage("Single message")
        sender.send_messages(single_message)

with ServiceBusClient.from_connection_string(connstr) as client:
    with client.get_queue_receiver(queue_name, max_wait_time=30) as receiver:
        messages = receiver.receive_messages()
```

### Receiving messages

| In v0.50 | Equivalent in v7 | Sample |
|---|---|---|
| `QueueClient.from_connection_string().get_receiver().fetch_next()  and ServiceBusClient.from_connection_string().get_queue().get_receiver().fetch_next()`| `ServiceBusClient.from_connection_string().get_queue_receiver().receive_messages()`| [Get a receiver and receive a single batch of messages](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/servicebus/azure-servicebus/samples/sync_samples/receive_queue.py) |
| `QueueClient.from_connection_string().get_receiver().peek()  and ServiceBusClient.from_connection_string().get_queue().get_receiver().peek()`| `ServiceBusClient.from_connection_string().get_queue_receiver().peek_messages()`| [Get a receiver and peek messages](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/receive_peek.py) |
| `QueueClient.from_connection_string().get_deadletter_receiver()  and ServiceBusClient.from_connection_string().get_queue().get_deadletter_receiver()`| `ServiceBusClient.from_connection_string().get_queue_receiver(sub_queue=ServiceBusSubQueue.DEAD_LETTER)`| [Get a deadletter receiver](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/receive_deadlettered_messages.py) |

### Settling messages

| In v0.50 | Equivalent in v7 | Sample |
|---|---|---|
| `message.complete()`| `receiver.complete_message(message)`| [Complete a message](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/servicebus/azure-servicebus/samples/sync_samples/receive_queue.py) |
| `message.abandon()`| `receiver.abandon_message(message)`| [Abandon a message](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/sample_code_servicebus.py) |
| `message.defer()`| `receiver.defer_message(message)`| [Defer a message](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/receive_deferred_message_queue.py) |
| `message.dead_letter()`| `receiver.dead_letter_message(message)`| [Dead letter a message](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/receive_deadlettered_messages.py) |

### Sending messages

| In v0.50 | Equivalent in v7 | Sample |
|---|---|---|
| `QueueClient.from_connection_string().send()  and ServiceBusClient.from_connection_string().get_queue().get_sender().send()`| `ServiceBusClient.from_connection_string().get_queue_sender().send_messages()`| [Get a sender and send a message](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/servicebus/azure-servicebus/samples/sync_samples/send_queue.py) |
| `queue_client.send(BatchMessage(["data 1", "data 2", ...]))`| `batch = queue_sender.create_message_batch()  batch.add_message(ServiceBusMessage("data 1"))  queue_sender.send_messages(batch)`| [Create and send a batch of messages](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/servicebus/azure-servicebus/samples/sync_samples/send_queue.py) |

### Scheduling messages and cancelling scheduled messages 

| In v0.50 | Equivalent in v7 | Sample |
|---|---|---|
| `queue_client.get_sender().schedule(schedule_time_utc, message1, message2)` | `sb_client.get_queue_sender().schedule_messages([message1, message2], schedule_time_utc)` | [Schedule messages](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/servicebus/azure-servicebus/samples/sync_samples/schedule_messages_and_cancellation.py) |
| `queue_client.get_sender().cancel_scheduled_messages(sequence_number1, sequence_number2)`| `sb_client.get_queue_sender().cancel_scheduled_messages([sequence_number1, sequence_number2])` | [Cancel scheduled messages](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/servicebus/azure-servicebus/samples/sync_samples/schedule_messages_and_cancellation.py)|

### Renewing lock on the received message
| In v0.50 | Equivalent in v7 | Sample |
|---|---|---|
| `message.renew_lock()` | `receiver.renew_message_lock(message)` | [Renew lock on the message](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/sample_code_servicebus.py) |

### Working with sessions

| In v0.50 | Equivalent in v7 | Sample |
|---|---|---|
| `queue_client.send(message, session='foo')  and queue_client.get_sender(session='foo').send(message)`| `sb_client.get_queue_sender().send_messages(Message('body', session_id='foo'))`| [Send a message to a session](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/servicebus/azure-servicebus/samples/sync_samples/session_send_receive.py) |
| `receiver.get_session_state()` | `receiver.session.get_state()` | [Set session state](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/session_send_receive.py)
| `receiver.set_session_state()` | `receiver.session.set_state()` | [Get session state](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/session_send_receive.py)
| `receiver.renew_lock()` | `receiver.session.renew_lock()` | [Renew lock on the session](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/session_send_receive.py)

### Working with UTC time
| In v0.50 | Equivalent in v7 | Note |
|---|---|---|
| `session.locked_until < datetime.now()`| `session.locked_until_utc < datetime.utcnow()`| All datetimes are now UTC and named as such|
| `message.scheduled_enqueue_time < datetime.now()`| `message.scheduled_enqueue_time_utc < datetime.utcnow()`| UTC Datetime normalization applies across all objects and datetime fields|

### Working with AutoLockRenewer
| In v0.50 | Equivalent in v7 | Sample |
|---|---|---|
| `azure.servicebus.AutoLockRenew().register(message)` | `azure.servicebus.AutoLockRenewer().register(receiver, message)` | [Auto lock renew a message received from a non-sessonful entity](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/servicebus/azure-servicebus/samples/sync_samples/auto_lock_renew.py) |
| `azure.servicebus.AutoLockRenew().register(session_receiver)` | `azure.servicebus.AutoLockRenewer().register(session_receiver, session_receiver.session)` | [Auto lock renew a session for sessionful receiver](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/auto_lock_renew.py) |
| `azure.servicebus.AutoLockRenew().shutdown()` | `azure.servicebus.AutoLockRenewer().close()` | [Close an auto-lock-renewer](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/servicebus/azure-servicebus/samples/sync_samples/auto_lock_renew.py) |

### Working with Message properties
| In v0.50 | Equivalent in v7 | Sample |
|---|---|---|
| `azure.servicebus.Message.user_properties` | `azure.servicebus.ServiceBusMessage.application_properties` | Some message properties have been renamed, e.g. accessing the application specific properties of a message. |

## Working with Administration Client

The management related operations like creating, updating, deleting and listing queues, topics, subscriptions or rules are to be done with the `ServiceBusAdministrationClient` which can be imported from the `azure.servicebus.management`. If one was relying on `control_client` available in v0.50, and cannot migrate to the `azure-mgmt-servicebus` package (or requires SAS based authentication for management), one would utilize this migration segment, otherwise, the aforementioned dedicated mgmt package should be used.

### Managing Queues
| In v0.50 | Equivalent in v7 | Sample |
|---|---|---|
| `azure.servicebus.control_client.ServiceBusService.get_queue(queue_name)` | `azure.servicebus.management.ServiceBusAdministrationClient.get_queue(queue_name)` | [get_queue](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_queue.py#L47) |
| `azure.servicebus.control_client.ServiceBusService.create_queue(queue_name)` | `azure.servicebus.management.ServiceBusAdministrationClient.create_queue(queue_name)` | [create_queue](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_queue.py#L26) |
| `azure.servicebus.control_client.ServiceBusService.delete_queue(queue_name)` | `azure.servicebus.management.ServiceBusAdministrationClient.delete_queue(queue_name)` | [delete_queue](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_queue.py#L33) |
| `azure.servicebus.control_client.ServiceBusService.list_queues()` | `azure.servicebus.management.ServiceBusAdministrationClient.list_queues()` | [list_queues](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_queue.py#L40) |

### Managing Topics
| In v0.50 | Equivalent in v7 | Sample |
|---|---|---|
| `azure.servicebus.control_client.ServiceBusService.get_topic(topic_name)` | `azure.servicebus.management.ServiceBusAdministrationClient.get_topic(topic_name)` | [get_topic](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_topic.py#L47) |
| `azure.servicebus.control_client.ServiceBusService.create_topic(topic_name)` | `azure.servicebus.management.ServiceBusAdministrationClient.create_topic(topic_name)` | [create_topic](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_topic.py#L26) |
| `azure.servicebus.control_client.ServiceBusService.get_topic(topic_name)` | `azure.servicebus.management.ServiceBusAdministrationClient.delete_topic(topic_name)` | [delete_topic](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_topic.py#L33) |
| `azure.servicebus.control_client.ServiceBusService.list_topics()` | `azure.servicebus.management.ServiceBusAdministrationClient.list_topics()` | [list_topics](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_topic.py#L40) |

### Managing Subscriptions
| In v0.50 | Equivalent in v7 | Sample |
|---|---|---|
| `azure.servicebus.control_client.ServiceBusService.get_subscription(topic_name, subscription_name)` | `azure.servicebus.management.ServiceBusAdministrationClient.get_subscription(topic_name, subscription_name)` |  [get_subscription](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_subscription.py#L48) |
| `azure.servicebus.control_client.ServiceBusService.create_subscription(topic_name, subscription_name)` | `azure.servicebus.management.ServiceBusAdministrationClient.create_subscription(topic_name, subscription_name)` |  [create_subscription](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_subscription.py#L27) |
| `azure.servicebus.control_client.ServiceBusService.delete_subscription(topic_name, subscription_name)` | `azure.servicebus.management.ServiceBusAdministrationClient.delete_subscription(topic_name, subscription_name)` |  [delete_subscription](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_subscription.py#L34) |
| `azure.servicebus.control_client.ServiceBusService.list_subscriptions(topic_name)` | `azure.servicebus.management.ServiceBusAdministrationClient.list_subscriptions(topic_name)` |  [list_subscriptions](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_subscription.py#L41) |

### Managing Rules
| In v0.50 | Equivalent in v7 | Sample |
|---|---|---|
| `azure.servicebus.control_client.ServiceBusService.get_rule(topic_name, subscription_name, rule_name)` | `azure.servicebus.management.ServiceBusAdministrationClient.get_rule(topic_name, subscription_name, rule_name)` | [get_rule](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_rule.py#L49) |
| `azure.servicebus.control_client.ServiceBusService.create_rule(topic_name, subscription_name, rule_name)` | `azure.servicebus.management.ServiceBusAdministrationClient.create_rule(topic_name, subscription_name, rule_name)` | [create_rule](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_rule.py#L28) |
| `azure.servicebus.control_client.ServiceBusService.delete_rule(topic_name, subscription_name, rule_name)` | `azure.servicebus.management.ServiceBusAdministrationClient.delete_rule(topic_name, subscription_name, rule_name)` | [delete_rule](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_rule.py#L35) |
| `azure.servicebus.control_client.ServiceBusService.list_rules(topic_name, subscription_name)` | `azure.servicebus.management.ServiceBusAdministrationClient.list_rules(topic_name, subscription_name)` | [list_rules](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/servicebus/azure-servicebus/samples/sync_samples/mgmt_rule.py#L42) |

## Migration samples

* [Receiving messages](#migrating-code-from-queueclient-and-receiver-to-servicebusreceiver-for-receiving-messages)
* [Sending messages](#migrating-code-from-queueclient-and-sender-to-servicebussender-for-sending-messages)

### Migrating code from `QueueClient` and `Receiver` to `ServiceBusReceiver` for receiving messages

In v0.50, `QueueClient` would be created directly or from the `ServiceBusClient.get_queue` method,
after which user would call `get_receiver` to obtain a receiver, calling `fetch_next` to receive a single 
batch of messages, or iterate over the receiver to receive continuously.

In v7, users should initialize the client via `ServiceBusClient.get_queue_receiver`.  Single-batch-receive
has been renamed to `receive_messages`, iterating over the receiver for continual message consumption has not changed.
It should also be noted that if a session receiver is desired, to use the `get_<queue/subscription>_receiver`
function and pass the `session_id` parameter.

For example, this code which keeps receiving from a partition in v0.50:

```python
client = ServiceBusClient.from_connection_string(CONNECTION_STR)
queue_client = client.get_queue(queue)

with queue_client.get_receiver(idle_timeout=1, mode=ReceiveSettleMode.PeekLock, prefetch=10) as receiver:

    # Receive list of messages as a batch
    batch = receiver.fetch_next(max_batch_size=10)
    for message in batch:
        print("Message: {}".format(message))
        message.complete()

    # Receive messages as a continuous generator
    for message in receiver:
        print("Message: {}".format(message))
        message.complete()
```

Becomes this in v7:
```python
with ServiceBusClient.from_connection_string(conn_str=CONNECTION_STR, receive_mode=ServiceBusReceiveMode.PEEK_LOCK) as client:

    with client.get_queue_receiver(queue_name=QUEUE_NAME) as receiver:
        batch = receiver.receive_messages(max_message_count=10, max_wait_time=5)
        for message in batch:
            print("Message: {}".format(message))
            receiver.complete_message(message)

        for message in receiver:
            print("Message: {}".format(message))
            receiver.complete_message(message)
```


### Migrating code from `QueueClient` and `Sender` to `ServiceBusSender` for sending messages

In v0.50, `QueueClient` would be created directly or from the `ServiceBusClient.get_queue` method,
after which user would call `get_sender` to obtain a sender, calling `send` to send a single or batch
of messages.  Send could also be called directly off of the `QueueClient`

In v7, users should initialize the client via `ServiceBusClient.get_queue_sender`.  Sending itself has not
changed, but currently does not support sending a list of messages in one call.  If this is desired, first
insert those messages into a batch.

So in v0.50:
```python
client = ServiceBusClient.from_connection_string(CONNECTION_STR)

queue_client = client.get_queue(queue)
with queue_client.get_sender() as sender:
    # Send one at a time.
    for i in range(100):
        message = Message("Sample message no. {}".format(i))
        sender.send(message)

    # Send as a batch.
    messages_to_batch = [Message("Batch message no. {}".format(i)) for i in range(10)]
    batch = BatchMessage(messages_to_batch)
    sender.send(batch)
```

In v7:
```python
with ServiceBusClient.from_connection_string(conn_str=CONNECTION_STR) as client:

    with client.get_queue_sender(queue_name=QUEUE_NAME) as sender:
        # Sending one at a time.
        for i in range(100):
            message = ServiceBusMessage("Sample message no. {}".format(i))
            sender.send_messages(message)

        # Send as a batch
        batch = new ServiceBusMessageBatch()
        for i in range(10):
            batch.add_message(ServiceBusMessage("Batch message no. {}".format(i)))
        sender.send_messages(batch)
```