Skip to content

Misc fixes#10000

Merged
JoshLove-msft merged 4 commits intoAzure:masterfrom
JoshLove-msft:misc-fixes
Feb 18, 2020
Merged

Misc fixes#10000
JoshLove-msft merged 4 commits intoAzure:masterfrom
JoshLove-msft:misc-fixes

Conversation

@JoshLove-msft
Copy link
Copy Markdown
Member

@JoshLove-msft JoshLove-msft commented Feb 15, 2020

  • Update client hierarchy based on our discussions
    • 4 clients with 2 abstract base classes
    • remove Receiver/Sender namespaces
  • Add RunOperation to RetryPolicy to help simplify retry logic
  • Remove SessionClient and put all session operations under new Session property on Receiver
  • Include SessionOptions in ctor overloads
  • Set the session filter when using a sessionful entity even if no session Id is populated

Fixes #9921

* Send session filter even if session Id is null if sessionOptions is
passed
* Remove SessionClient
These analyzers are blocked by https://github.com/Azure/azure-sdk-tools/issues/127
-->
<NoWarn>
$(NoWarn);
Copy link
Copy Markdown
Member Author

@JoshLove-msft JoshLove-msft Feb 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows us to not match the ClientOption type names exactly with the Client type.
This is useful for SenderClientOptions. We can remove this if we end up creating explicit option types for each client.

/// </summary>
///
public ServiceBusRetryOptions Options { get; }
public override ServiceBusRetryOptions Options { get; }
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exposing this in ServiceBusRetryPolicy to provide access to the default timeout.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that you want to do this; the options type is mutable and intent of having this only on the internal implementation type was to ensure that we do not allow callers to change the options after the client was constructed.

If you're going to elevate, I'd suggest making the member internal.

Comment thread sdk/servicebus/Azure.Messaging.ServiceBus/src/Core/TransportConsumer.cs Outdated
Comment thread sdk/servicebus/Azure.Messaging.ServiceBus/src/ServiceBusRetryPolicy.cs Outdated
@JoshLove-msft JoshLove-msft marked this pull request as ready for review February 17, 2020 20:08
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this type be aware of the transport in use? For example, if we're doing JMS instead of AMQP or have a recorded test transport at some point, we would have to potentially extend this class since it has logic around AmqpException.

Would it make sense to, maybe, make this an extension method in the Amqp namespace, so that the AMQP transport types can access it, but other transport types could have a localized version with potentially different logic? (TranslateServiceException that is called was scoped to that AMQP namespace in Event Hubs; I don't believe that it moved moved during the Service Bus adoption)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it probably shouldn't know about AMQP. I think the only thing that wouldn't apply generically though is this exception type, so I'm not sure that it is worth moving this to an extension method. What do you think about intoducing the concept of a TransportException and using that here instead? AmqpException would derive from TransportException.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not opposed to a transport exception, but I'm not sure it'll work the way that you're proposing. The AmqpException is part of the AMQP library and not one of ours, unfortunately. You'd have to wrap it. They do some specific things with how it wraps inner exceptions and such, which is why that translation method came into play, I'm not sure that we'd want that to be applied generically.... so maybe that translate could live in the AMQP area and if no other translations apply, wrap the AMQP exception in a transport exception and bubble it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to figure this out as part of #9879


try
{
TimeSpan tryTimeout = CalculateTryTimeout(0);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The per-try timeout doesn't appear to be considered within the operation. Should the signature for operation change to Func<TimeSpan, Task> so that it can be passed in and allow the operation itself to control whether it obeys the requested timeout period?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for context, most of the underlying AMQP library is based on timeouts rather than obeying cancellation. The closer you are to the transport, the more likely that you'll want/need to know the base timeout so you can pass it along.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, if we are going to support the per-try timeout, we would need to change to Func<TimeSpan, Task>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


namespace Azure.Messaging.ServiceBus.Core
{
internal abstract class TransportConnectionScope : IDisposable
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Missing doc comment for the class.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will cover as part of doc updates

/// </summary>
///
public ServiceBusRetryOptions Options { get; }
public override ServiceBusRetryOptions Options { get; }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that you want to do this; the options type is mutable and intent of having this only on the internal implementation type was to ensure that we do not allow callers to change the options after the client was constructed.

If you're going to elevate, I'd suggest making the member internal.

ReceivingAmqpLink openedLink = null;
await _retryPolicy.RunOperation(
async () =>
openedLink = await _consumer.ReceiveLink.GetOrCreateAsync(_retryPolicy.Options.TryTimeout).ConfigureAwait(false),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This confuses me. The point of the transport consumer is to abstract the concept of AMQP links away from callers, especially those outside of the AMQP layer. In its current form , this is leaking the abstraction. This makes it much harder to inject a transport consumer for behavioral overrides to unit test and to potentially add other transports (like a recording framework) in the future that may not be link-based.

I could be missing something, but shouldn't we be having the details of getting the session on the transport consumer or another transport client? I'd also advise against exposing the link directly, to avoid leaking that abstraction and force the consumer to be extended instead.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation can be moved down to the consumer layer.

/// <summary>
///
/// </summary>
public ServiceBusConnection Connection { get; set; }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this was a detail from the design discussions that I missed and, if so, apologies but.... having the connection here feels orthogonal to the concerns of a session. The connection itself isn't session-aware or required to do something session-related?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah our idea was that when using sessions, you need to provide a Connection. I think this may change though so this is still pretty tentative.

///
/// <remarks>
/// If the connection string is copied from the Service Bus namespace, it will likely not contain the name of the desired Service Bus entity,
/// which is needed. In this case, the name can be added manually by adding ";EntityPath=[[ Service Bus entity NAME ]]" to the end of the
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: The entity path capitalization is weird.

@@ -27,7 +26,7 @@ namespace Azure.Messaging.ServiceBus
///
/// <seealso href="https://docs.microsoft.com/en-us/Azure/event-hubs/event-hubs-about" />
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: You may want to update the reference on line 28.

{
Argument.AssertNotNull(retryPolicy, nameof(retryPolicy));
return InnerClient.CreateConsumer(retryPolicy, ownerLevel, prefetchCount, sessionId);
return InnerClient.CreateConsumer(retryPolicy, ownerLevel, prefetchCount, sessionId, isSessionReceiver);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point, we probably want to consider unifying terminology; if we're calling these "Sender/Receiver" rather than "Producer/Consumer" we'll probably want to update the member names.

@nemakam nemakam removed their request for review February 18, 2020 20:51
@JoshLove-msft JoshLove-msft merged commit 8713e3f into Azure:master Feb 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Determine how to implement retries

2 participants