- 
                Notifications
    
You must be signed in to change notification settings  - Fork 5.1k
 
ServiceBusRetryPolicy generic overloads to avoid closure capturing #19522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ServiceBusRetryPolicy generic overloads to avoid closure capturing #19522
Conversation
| 
           Thank you for your contribution @danielmarbach! We will review the pull request and get back to you soon.  | 
    
| /// <param name="timeout"></param> | ||
| /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param> | ||
| /// | ||
| internal virtual async Task SendBatchInternalAsync( | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is internal virtual, so I wasn't sure if I'm allowed to change it or not. Please advise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes feel free to change.
| cancellationToken).ConfigureAwait(false), | ||
| token).ConfigureAwait(false), | ||
| this, | ||
| messageBatch.AsEnumerable<ServiceBusMessage>(), | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was fairly certain this is an OK change since the batch has a list internally. I couldn't see a reason why it would be required to cast to IEnumerable over and over again during retries. I preserved though the conversion to the AmqpMessage which seems to be the crucial part
        
          
                sdk/servicebus/Azure.Messaging.ServiceBus/src/Primitives/ServiceBusRetryPolicy.cs
              
                Outdated
          
            Show resolved
            Hide resolved
        
              
          
                sdk/servicebus/Azure.Messaging.ServiceBus/src/Amqp/AmqpSender.cs
              
                Outdated
          
            Show resolved
            Hide resolved
        
              
          
                sdk/servicebus/Azure.Messaging.ServiceBus/src/Amqp/AmqpReceiver.cs
              
                Outdated
          
            Show resolved
            Hide resolved
        
      | return await createBatchTask.ConfigureAwait(false); | ||
| } | ||
| 
               | 
          ||
| internal async ValueTask<TransportMessageBatch> CreateMessageBatchInternalAsync( | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Example
Before
          if (num1 != 0)
          {
            this.\u003C\u003E8__1 = new AmqpSender.\u003C\u003Ec__DisplayClass16_0();
            this.\u003C\u003E8__1.\u003C\u003E4__this = this.\u003C\u003E4__this;
            this.\u003C\u003E8__1.options = this.options;
            this.\u003C\u003E8__1.messageBatch = (TransportMessageBatch) null;
            // ISSUE: method pointer
            configuredTaskAwaiter = amqpSender._retryPolicy.RunOperation(new Func<TimeSpan, Task>((object) this.\u003C\u003E8__1, __methodptr(\u003CCreateMessageBatchAsync\u003Eb__0)), (TransportConnectionScope) amqpSender._connectionScope, this.cancellationToken).ConfigureAwait(false).GetAwaiter();
            if (!configuredTaskAwaiter.IsCompleted)
            {
              this.\u003C\u003E1__state = num2 = 0;
              this.\u003C\u003Eu__1 = configuredTaskAwaiter;
              // ISSUE: cast to a reference type
              // ISSUE: cast to a reference type
              ((AsyncValueTaskMethodBuilder<TransportMessageBatch>) ref this.\u003C\u003Et__builder).AwaitUnsafeOnCompleted<ConfiguredTaskAwaitable.ConfiguredTaskAwaiter, AmqpSender.\u003CCreateMessageBatchAsync\u003Ed__16>((M0&) ref configuredTaskAwaiter, (M1&) ref this);
              return;
            }
          }
After
          if (num1 != 0)
          {
            // ISSUE: method pointer
            configuredTaskAwaiter = t1._retryPolicy.RunOperation<AmqpSender, CreateMessageBatchOptions, TransportMessageBatch>(AmqpSender.\u003C\u003Ec.\u003C\u003E9__16_0 ?? (AmqpSender.\u003C\u003Ec.\u003C\u003E9__16_0 = new Func<AmqpSender, CreateMessageBatchOptions, TimeSpan, CancellationToken, Task<TransportMessageBatch>>((object) AmqpSender.\u003C\u003Ec.\u003C\u003E9, __methodptr(\u003CCreateMessageBatchAsync\u003Eb__16_0))), t1, this.options, (TransportConnectionScope) t1._connectionScope, this.cancellationToken).ConfigureAwait(false).GetAwaiter();
            if (!configuredTaskAwaiter.IsCompleted)
            {
              this.\u003C\u003E1__state = num2 = 0;
              this.\u003C\u003Eu__1 = configuredTaskAwaiter;
              // ISSUE: cast to a reference type
              // ISSUE: cast to a reference type
              ((AsyncValueTaskMethodBuilder<TransportMessageBatch>) ref this.\u003C\u003Et__builder).AwaitUnsafeOnCompleted<ConfiguredTaskAwaitable<TransportMessageBatch>.ConfiguredTaskAwaiter, AmqpSender.\u003CCreateMessageBatchAsync\u003Ed__16>((M0&) ref configuredTaskAwaiter, (M1&) ref this);
              return;
            }
          }
So we are saving two allocations now for every request and this on every callsite touched by this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this ever be null? I tried to do in the ScheduleMessageInternalAsync return sequenceNumbers ?? Array.Empty<long>() and flow analysis claimed it cannot be null so I wonder if this is really needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it can be null.
        
          
                sdk/servicebus/Azure.Messaging.ServiceBus/src/Amqp/AmqpSender.cs
              
                Outdated
          
            Show resolved
            Hide resolved
        
      | 
           Getting now a bunch of   | 
    
458d86b    to
    0420017      
    Compare
  
            
          
                sdk/servicebus/Azure.Messaging.ServiceBus/src/Primitives/VoidResult.cs
              
                Outdated
          
            Show resolved
            Hide resolved
        
      | 
           Hope this time the build will not be canceled. It looks though like master is also in a weird state  | 
    
| 
           Would you like me to squash things a bit to clean up the history or ok as is?  | 
    
| 
           /azp run net - servicebus - tests  | 
    
| 
          
Azure Pipelines successfully started running 1 pipeline(s). | 
    
          
 No need it will get squashed when merging.  | 
    
| 
           /azp run net - servicebus - ci  | 
    
| 
          
Azure Pipelines successfully started running 1 pipeline(s). | 
    
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, @danielmarbach, for identifying the opportunity here and for making the change. The current form looks good to me structurally. I have some concerns around some of the naming - I find the abbreviations make it harder to read and understand context at a glance. I'd really appreciate if we could err on the side of more expressive names.
I'm going to defer the call on final approval to @JoshLove-msft.
        
          
                sdk/servicebus/Azure.Messaging.ServiceBus/src/Amqp/AmqpSender.cs
              
                Outdated
          
            Show resolved
            Hide resolved
        
      | return messageBatch; | ||
| return await _retryPolicy.RunOperation(static async (value, timeout, _) => | ||
| { | ||
| var (sender, ops) = value; | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:  It's not clear to me what ops is without looking at the original context.   Can we go with options again?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as abobeu
        
          
                sdk/servicebus/Azure.Messaging.ServiceBus/src/Amqp/AmqpSender.cs
              
                Outdated
          
            Show resolved
            Hide resolved
        
              
          
                sdk/servicebus/Azure.Messaging.ServiceBus/src/Amqp/AmqpReceiver.cs
              
                Outdated
          
            Show resolved
            Hide resolved
        
              
          
                sdk/servicebus/Azure.Messaging.ServiceBus/src/Primitives/ServiceBusRetryPolicy.cs
              
                Outdated
          
            Show resolved
            Hide resolved
        
      | 
           /azp run net - servicebus - tests  | 
    
| 
          
Azure Pipelines successfully started running 1 pipeline(s). | 
    
Fixes #19126
All SDK Contribution checklist:
This checklist is used to make sure that common guidelines for a pull request are followed.
Draftmode if it is:General Guidelines and Best Practices
Testing Guidelines
SDK Generation Guidelines
*.csprojandAssemblyInfo.csfiles have been updated with the new version of the SDK. Please double check nuget.org current release version.Additional management plane SDK specific contribution checklist:
Note: Only applies to
Microsoft.Azure.Management.[RP]orAzure.ResourceManager.[RP]Management plane SDK Troubleshooting
new servicelabel and/or contact assigned reviewer.Verify Code Generationstep, please ensure:generate.ps1/cmdto generate this PR instead of callingautorestdirectly.Please pay attention to the @microsoft.csharp version output after running generate.ps1. If it is lower than current released version (2.3.82), please run it again as it should pull down the latest version,
Old outstanding PR cleanup
Please note:
If PRs (including draft) has been out for more than 60 days and there are no responses from our query or followups, they will be closed to maintain a concise list for our reviewers.