-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
BatchClient.cs
300 lines (251 loc) · 12.1 KB
/
BatchClient.cs
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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
namespace Microsoft.Azure.Batch
{
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Protocol;
using Rest;
/// <summary>
/// The dispose pattern sets all references to null.
/// Put all references into this box.
///
/// ONLY ACCESS VIA GetStateThrowIfNotOpen() method!
///
/// </summary>
internal class BatchClientDisposableStateBox
{
private readonly BatchClient _parentBatchClient;
private readonly Lazy<ApplicationOperations> _applicationOperations;
private readonly Lazy<CertificateOperations> _certificateOperations;
private readonly Lazy<JobOperations> _jobOperations;
private readonly Lazy<JobScheduleOperations> _jobScheduleOperations;
private readonly Lazy<PoolOperations> _poolOperations;
private readonly Lazy<Utilities> _utilities;
public IList<BatchClientBehavior> CustomBehaviors;
public IProtocolLayer ProtocolLayer;
public BatchClientDisposableStateBox(BatchClient parentBatchClient)
{
this._parentBatchClient = parentBatchClient;
this._applicationOperations = new Lazy<ApplicationOperations>(() => new ApplicationOperations(this._parentBatchClient, this.CustomBehaviors));
this._certificateOperations = new Lazy<CertificateOperations>(() => new CertificateOperations(this._parentBatchClient, this.CustomBehaviors));
this._jobOperations = new Lazy<JobOperations>(() => new JobOperations(this._parentBatchClient, this.CustomBehaviors));
this._jobScheduleOperations = new Lazy<JobScheduleOperations>(() => new JobScheduleOperations(this._parentBatchClient, this.CustomBehaviors));
this._poolOperations = new Lazy<PoolOperations>(() => new PoolOperations(this._parentBatchClient, this.CustomBehaviors));
this._utilities = new Lazy<Utilities>(() => new Utilities(this._parentBatchClient, this.CustomBehaviors));
this.CustomBehaviors = new List<BatchClientBehavior>();
}
public ApplicationOperations ApplicationOperations => this._applicationOperations.Value;
public CertificateOperations CertificateOperations => this._certificateOperations.Value;
public JobOperations JobOperations => this._jobOperations.Value;
public JobScheduleOperations JobScheduleOperations => this._jobScheduleOperations.Value;
public PoolOperations PoolOperations => this._poolOperations.Value;
public Utilities Utilities => this._utilities.Value;
}
/// <summary>
/// A client for an Azure Batch account, used to access the Batch service.
/// </summary>
public class BatchClient : IDisposable
{
private BatchClientDisposableStateBox _disposableStateBox; // null state box signals that the instance is closed
private bool _disposed; // used for dispose pattern
private readonly object _closeLocker = new object();
#region // constructors
private BatchClient()
{
_disposableStateBox = new BatchClientDisposableStateBox(this);
//
// Add custom behaviors which are by default on every batch client
//
this.CustomBehaviors.Add(RetryPolicyProvider.ExponentialRetryProvider(TimeSpan.FromSeconds(1), 6));
//Add default AddTaskResultHandler
this.CustomBehaviors.Add(new AddTaskCollectionResultHandler(AddTaskCollectionResultHandler.DefaultAddTaskCollectionResultHandler));
}
private BatchClient(Auth.BatchSharedKeyCredentials credentials) : this()
{
ServiceClientCredentials proxyCredentials = new Protocol.BatchSharedKeyCredential(credentials.AccountName, credentials.KeyValue);
this.ProtocolLayer = new ProtocolLayer(credentials.BaseUrl, proxyCredentials);
}
private BatchClient(Auth.BatchTokenCredentials credentials) : this()
{
ServiceClientCredentials proxyCredentials = new TokenCredentials(new BatchTokenProvider(credentials.TokenProvider));
this.ProtocolLayer = new ProtocolLayer(credentials.BaseUrl, proxyCredentials);
}
private BatchClient(Protocol.BatchServiceClient customRestClient)
: this()
{
this.ProtocolLayer = new ProtocolLayer(customRestClient);
}
/// <summary>
/// Holds the protocol layer to be used for this client instance.
/// This enables "mock"ing the protocol layer for testing.
/// </summary>
internal BatchClient(IProtocolLayer protocolLayer)
: this()
{
this.ProtocolLayer = protocolLayer;
}
#endregion Constructors
#region IInheritedBehaviors
/// <summary>
/// Gets or sets a list of behaviors that modify or customize requests to the Batch service.
/// </summary>
/// <remarks>
/// <para>These behaviors are inherited by child objects.</para>
/// <para>Modifications are applied in the order of the collection. The last write wins.</para>
/// </remarks>
public IList<BatchClientBehavior> CustomBehaviors
{
get
{
return GetStateThrowIfNotOpen().CustomBehaviors;
}
set
{
GetStateThrowIfNotOpen().CustomBehaviors = value;
}
}
#endregion IInheritedBehaviors
#region // BatchClient
/// <summary>
/// Gets an <see cref="ApplicationOperations"/> for performing application-related operations on the associated account.
/// </summary>
public ApplicationOperations ApplicationOperations => GetStateThrowIfNotOpen().ApplicationOperations;
/// <summary>
/// Gets a <see cref="CertificateOperations"/> for performing certificate-related operations on the associated account.
/// </summary>
public CertificateOperations CertificateOperations => GetStateThrowIfNotOpen().CertificateOperations;
/// <summary>
/// Gets a <see cref="JobOperations"/> for performing job-related operations on the associated account.
/// </summary>
public JobOperations JobOperations => GetStateThrowIfNotOpen().JobOperations;
/// <summary>
/// Gets a <see cref="JobScheduleOperations"/> for performing job schedule-related operations on the associated account.
/// </summary>
public JobScheduleOperations JobScheduleOperations => GetStateThrowIfNotOpen().JobScheduleOperations;
/// <summary>
/// Gets a <see cref="PoolOperations"/> for performing pool-related operations on the associated account.
/// </summary>
public PoolOperations PoolOperations => GetStateThrowIfNotOpen().PoolOperations;
/// <summary>
/// Gets a <see cref="Utilities"/> object containing utility methods for orchestrating multiple Batch operations.
/// </summary>
public Utilities Utilities => GetStateThrowIfNotOpen().Utilities;
/// <summary>
/// Creates an instance of <see cref="BatchClient" />.
/// </summary>
/// <param name="credentials">The Batch account credentials.</param>
/// <returns>An instance of <see cref="Microsoft.Azure.Batch.Protocol.BatchServiceClient"/>.</returns>
public static BatchClient Open(Auth.BatchSharedKeyCredentials credentials)
{
if (null == credentials)
{
throw new ArgumentNullException(nameof(credentials));
}
return new BatchClient(credentials);
}
/// <summary>
/// Creates an instance of <see cref="BatchClient" />.
/// </summary>
/// <param name="credentials">The Azure Active Directory Batch account credentials.</param>
/// <returns>An instance of <see cref="Microsoft.Azure.Batch.Protocol.BatchServiceClient"/>.</returns>
public static BatchClient Open(Auth.BatchTokenCredentials credentials)
{
if (null == credentials)
{
throw new ArgumentNullException(nameof(credentials));
}
return new BatchClient(credentials);
}
/// <summary>
/// Blocking call that creates an instance of <see cref="BatchClient"/> associated with the specified <see cref="Microsoft.Azure.Batch.Protocol.BatchServiceClient"/>.
/// </summary>
/// <param name="restClient">The instance of <see cref="Microsoft.Azure.Batch.Protocol.BatchServiceClient"/> to use for all calls made to the Batch Service. It will not be disposed when BatchClient is disposed.</param>
/// <returns>An instance of <see cref="Microsoft.Azure.Batch.Protocol.BatchServiceClient"/>.</returns>
public static BatchClient Open(Protocol.BatchServiceClient restClient)
{
if (null == restClient)
{
throw new ArgumentNullException(nameof(restClient));
}
return new BatchClient(restClient);
}
#endregion // BatchClient
#region // IDisposable
/// <summary>
/// Releases the unmanaged resources and disposes of the managed resources used by the <see cref="Microsoft.Azure.Batch.BatchClient"/>.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged resources used by the <see cref="BatchClient"/>, and optionally disposes of managed resources.
/// </summary>
/// <param name="disposing">Indicates whether the object is being disposed or finalized. If true, the object is
/// being disposed and can dispose managed resource. If false, the object is being finalized and should only
/// release unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
// IDisposable only section
lock (this._closeLocker)
{
if (this._disposableStateBox != null)
{
IProtocolLayer localProto = this.ProtocolLayer;
localProto.Dispose();
this._disposableStateBox = null; // null state box signals that the instance is closed
}
}
}
_disposed = true;
}
#endregion // IDisposable
#region internal/private methods
/// <summary>
/// Enforces that current instance is not "close".
/// All access to disposable state should go through this routine.
/// </summary>
/// <returns></returns>
internal BatchClientDisposableStateBox GetStateThrowIfNotOpen()
{
BatchClientDisposableStateBox localState = _disposableStateBox;
if (null != localState)
{
return localState;
}
// TODO: BatchException is not yet ready for this... do we need to create simpler BatchExceptions for stuff like this?
throw new InvalidOperationException(BatchErrorMessages.BatchClientIsClosed);
}
/// <summary>
/// Holds the protocol layer to be used for this client instance.
/// This enables "mock"ing the protocol layer for testing.
///
/// Since 100% of all calls indirect through this property, it
/// provides a single place to immediately stop all (new) call attempts
/// when the underlying BatchClient is closed.
/// </summary>
internal IProtocolLayer ProtocolLayer
{
get
{
IProtocolLayer localProto = GetStateThrowIfNotOpen().ProtocolLayer;
return localProto;
}
private set
{
GetStateThrowIfNotOpen().ProtocolLayer = value;
}
}
#endregion internal/private methods
}
}