Skip to content

Commit 6807e41

Browse files
updated idempotency logic (Azure#31790)
1 parent 83e44b6 commit 6807e41

18 files changed

+180
-93
lines changed

sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallAutomationAsyncClient.java

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,12 @@ Mono<Response<CreateCallResult>> createCallWithResponseInternal(CreateCallOption
125125
try {
126126
context = context == null ? Context.NONE : context;
127127
CreateCallRequestInternal request = getCreateCallRequestInternal(createCallOptions);
128-
if (createCallOptions.getRepeatabilityHeaders() == null) {
129-
RepeatabilityHeaders autoRepeatabilityHeaders = new RepeatabilityHeaders(UUID.randomUUID(), Instant.now());
130-
createCallOptions.setRepeatabilityHeaders(autoRepeatabilityHeaders);
131-
}
128+
129+
createCallOptions.setRepeatabilityHeaders(handleApiIdempotency(createCallOptions.getRepeatabilityHeaders()));
132130

133131
return serverCallingInternal.createCallWithResponseAsync(request,
134-
createCallOptions.getRepeatabilityHeaders().getRepeatabilityRequestId(),
135-
createCallOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat(),
132+
createCallOptions.getRepeatabilityHeaders() != null ? createCallOptions.getRepeatabilityHeaders().getRepeatabilityRequestId() : null,
133+
createCallOptions.getRepeatabilityHeaders() != null ? createCallOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat() : null,
136134
context)
137135
.onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create)
138136
.map(response -> {
@@ -227,10 +225,7 @@ Mono<Response<AnswerCallResult>> answerCallWithResponseInternal(AnswerCallOption
227225
.setIncomingCallContext(answerCallOptions.getIncomingCallContext())
228226
.setCallbackUri(answerCallOptions.getCallbackUrl());
229227

230-
if (answerCallOptions.getRepeatabilityHeaders() == null) {
231-
RepeatabilityHeaders autoRepeatabilityHeaders = new RepeatabilityHeaders(UUID.randomUUID(), Instant.now());
232-
answerCallOptions.setRepeatabilityHeaders(autoRepeatabilityHeaders);
233-
}
228+
answerCallOptions.setRepeatabilityHeaders(handleApiIdempotency(answerCallOptions.getRepeatabilityHeaders()));
234229

235230
if (answerCallOptions.getMediaStreamingConfiguration() != null) {
236231
MediaStreamingConfigurationInternal mediaStreamingConfigurationInternal =
@@ -241,8 +236,8 @@ Mono<Response<AnswerCallResult>> answerCallWithResponseInternal(AnswerCallOption
241236

242237

243238
return serverCallingInternal.answerCallWithResponseAsync(request,
244-
answerCallOptions.getRepeatabilityHeaders().getRepeatabilityRequestId(),
245-
answerCallOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat(),
239+
answerCallOptions.getRepeatabilityHeaders() != null ? answerCallOptions.getRepeatabilityHeaders().getRepeatabilityRequestId() : null,
240+
answerCallOptions.getRepeatabilityHeaders() != null ? answerCallOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat() : null,
246241
context)
247242
.onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create)
248243
.map(response -> {
@@ -296,14 +291,11 @@ Mono<Response<Void>> redirectCallWithResponseInternal(RedirectCallOptions redire
296291
.setIncomingCallContext(redirectCallOptions.getIncomingCallContext())
297292
.setTarget(CommunicationIdentifierConverter.convert(redirectCallOptions.getTarget()));
298293

299-
if (redirectCallOptions.getRepeatabilityHeaders() == null) {
300-
RepeatabilityHeaders autoRepeatabilityHeaders = new RepeatabilityHeaders(UUID.randomUUID(), Instant.now());
301-
redirectCallOptions.setRepeatabilityHeaders(autoRepeatabilityHeaders);
302-
}
294+
redirectCallOptions.setRepeatabilityHeaders(handleApiIdempotency(redirectCallOptions.getRepeatabilityHeaders()));
303295

304296
return serverCallingInternal.redirectCallWithResponseAsync(request,
305-
redirectCallOptions.getRepeatabilityHeaders().getRepeatabilityRequestId(),
306-
redirectCallOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat(),
297+
redirectCallOptions.getRepeatabilityHeaders() != null ? redirectCallOptions.getRepeatabilityHeaders().getRepeatabilityRequestId() : null,
298+
redirectCallOptions.getRepeatabilityHeaders() != null ? redirectCallOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat() : null,
307299
context)
308300
.onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create);
309301
} catch (RuntimeException ex) {
@@ -348,14 +340,11 @@ Mono<Response<Void>> rejectCallWithResponseInternal(RejectCallOptions rejectCall
348340
request.setCallRejectReason(CallRejectReasonInternal.fromString(rejectCallOptions.getCallRejectReason().toString()));
349341
}
350342

351-
if (rejectCallOptions.getRepeatabilityHeaders() == null) {
352-
RepeatabilityHeaders autoRepeatabilityHeaders = new RepeatabilityHeaders(UUID.randomUUID(), Instant.now());
353-
rejectCallOptions.setRepeatabilityHeaders(autoRepeatabilityHeaders);
354-
}
343+
rejectCallOptions.setRepeatabilityHeaders(handleApiIdempotency(rejectCallOptions.getRepeatabilityHeaders()));
355344

356345
return serverCallingInternal.rejectCallWithResponseAsync(request,
357-
rejectCallOptions.getRepeatabilityHeaders().getRepeatabilityRequestId(),
358-
rejectCallOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat(),
346+
rejectCallOptions.getRepeatabilityHeaders() != null ? rejectCallOptions.getRepeatabilityHeaders().getRepeatabilityRequestId() : null,
347+
rejectCallOptions.getRepeatabilityHeaders() != null ? rejectCallOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat() : null,
359348
context)
360349
.onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create);
361350
} catch (RuntimeException ex) {
@@ -387,4 +376,24 @@ public CallRecordingAsync getCallRecordingAsync() {
387376
contentDownloader, httpPipelineInternal, resourceEndpoint);
388377
}
389378
//endregion
379+
380+
//region helper functions
381+
/***
382+
* Make sure repeatability headers of the request are correctly set.
383+
*
384+
* @return a verified RepeatabilityHeaders object.
385+
*/
386+
static RepeatabilityHeaders handleApiIdempotency(RepeatabilityHeaders repeatabilityHeaders) {
387+
// This case means user did not disable idempotency
388+
if (repeatabilityHeaders != null) {
389+
// This means user never set the repeatability headers manually.
390+
if (repeatabilityHeaders.getRepeatabilityRequestId().equals(UUID.fromString("0-0-0-0-0"))
391+
&& repeatabilityHeaders.getRepeatabilityFirstSent() == Instant.MIN) {
392+
repeatabilityHeaders = new RepeatabilityHeaders(UUID.randomUUID(), Instant.now());
393+
} // Else do nothing, use the repeatability headers that user specified.
394+
} // Else do nothing, since the user disabled idempotency. Leave it as null.
395+
396+
return repeatabilityHeaders;
397+
}
398+
//endregion
390399
}

sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallConnectionAsync.java

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@
4242
import reactor.core.publisher.Mono;
4343

4444
import java.net.URISyntaxException;
45-
import java.time.Instant;
4645
import java.util.List;
47-
import java.util.UUID;
4846
import java.util.stream.Collectors;
4947

5048
import static com.azure.core.util.FluxUtil.monoError;
@@ -142,14 +140,11 @@ Mono<Response<Void>> hangUpWithResponseInternal(HangUpOptions hangUpOptions, Con
142140
try {
143141
context = context == null ? Context.NONE : context;
144142

145-
if (hangUpOptions.getRepeatabilityHeaders() == null) {
146-
RepeatabilityHeaders autoRepeatabilityHeaders = new RepeatabilityHeaders(UUID.randomUUID(), Instant.now());
147-
hangUpOptions.setRepeatabilityHeaders(autoRepeatabilityHeaders);
148-
}
143+
hangUpOptions.setRepeatabilityHeaders(handleApiIdempotency(hangUpOptions.getRepeatabilityHeaders()));
149144

150145
return (hangUpOptions.getIsForEveryone() ? callConnectionInternal.terminateCallWithResponseAsync(callConnectionId,
151-
hangUpOptions.getRepeatabilityHeaders().getRepeatabilityRequestId(),
152-
hangUpOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat(),
146+
hangUpOptions.getRepeatabilityHeaders() != null ? hangUpOptions.getRepeatabilityHeaders().getRepeatabilityRequestId() : null,
147+
hangUpOptions.getRepeatabilityHeaders() != null ? hangUpOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat() : null,
153148
context)
154149
: callConnectionInternal.hangupCallWithResponseAsync(callConnectionId, context))
155150
.onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create);
@@ -272,14 +267,11 @@ Mono<Response<TransferCallResult>> transferToParticipantCallWithResponseInternal
272267
.setUserToUserInformation(transferToParticipantCallOptions.getUserToUserInformation())
273268
.setOperationContext(transferToParticipantCallOptions.getOperationContext());
274269

275-
if (transferToParticipantCallOptions.getRepeatabilityHeaders() == null) {
276-
RepeatabilityHeaders autoRepeatabilityHeaders = new RepeatabilityHeaders(UUID.randomUUID(), Instant.now());
277-
transferToParticipantCallOptions.setRepeatabilityHeaders(autoRepeatabilityHeaders);
278-
}
270+
transferToParticipantCallOptions.setRepeatabilityHeaders(handleApiIdempotency(transferToParticipantCallOptions.getRepeatabilityHeaders()));
279271

280272
return callConnectionInternal.transferToParticipantWithResponseAsync(callConnectionId, request,
281-
transferToParticipantCallOptions.getRepeatabilityHeaders().getRepeatabilityRequestId(),
282-
transferToParticipantCallOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat(),
273+
transferToParticipantCallOptions.getRepeatabilityHeaders() != null ? transferToParticipantCallOptions.getRepeatabilityHeaders().getRepeatabilityRequestId() : null,
274+
transferToParticipantCallOptions.getRepeatabilityHeaders() != null ? transferToParticipantCallOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat() : null,
283275
context)
284276
.onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create)
285277
.map(response ->
@@ -332,14 +324,11 @@ Mono<Response<AddParticipantsResult>> addParticipantsWithResponseInternal(AddPar
332324
request.setInvitationTimeoutInSeconds((int) addParticipantsOptions.getInvitationTimeout().getSeconds());
333325
}
334326

335-
if (addParticipantsOptions.getRepeatabilityHeaders() == null) {
336-
RepeatabilityHeaders autoRepeatabilityHeaders = new RepeatabilityHeaders(UUID.randomUUID(), Instant.now());
337-
addParticipantsOptions.setRepeatabilityHeaders(autoRepeatabilityHeaders);
338-
}
327+
addParticipantsOptions.setRepeatabilityHeaders(handleApiIdempotency(addParticipantsOptions.getRepeatabilityHeaders()));
339328

340329
return callConnectionInternal.addParticipantWithResponseAsync(callConnectionId, request,
341-
addParticipantsOptions.getRepeatabilityHeaders().getRepeatabilityRequestId(),
342-
addParticipantsOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat(),
330+
addParticipantsOptions.getRepeatabilityHeaders() != null ? addParticipantsOptions.getRepeatabilityHeaders().getRepeatabilityRequestId() : null,
331+
addParticipantsOptions.getRepeatabilityHeaders() != null ? addParticipantsOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat() : null,
343332
context)
344333
.onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create)
345334
.map(response -> new SimpleResponse<>(response, AddParticipantsResponseConstructorProxy.create(response.getValue())));
@@ -380,18 +369,15 @@ Mono<Response<RemoveParticipantsResult>> removeParticipantsWithResponseInternal(
380369
List<CommunicationIdentifierModel> participantModels = removeParticipantsOptions.getParticipants()
381370
.stream().map(CommunicationIdentifierConverter::convert).collect(Collectors.toList());
382371

383-
if (removeParticipantsOptions.getRepeatabilityHeaders() == null) {
384-
RepeatabilityHeaders autoRepeatabilityHeaders = new RepeatabilityHeaders(UUID.randomUUID(), Instant.now());
385-
removeParticipantsOptions.setRepeatabilityHeaders(autoRepeatabilityHeaders);
386-
}
372+
removeParticipantsOptions.setRepeatabilityHeaders(handleApiIdempotency(removeParticipantsOptions.getRepeatabilityHeaders()));
387373

388374
RemoveParticipantsRequestInternal request = new RemoveParticipantsRequestInternal()
389375
.setParticipantsToRemove(participantModels)
390376
.setOperationContext(removeParticipantsOptions.getOperationContext());
391377

392378
return callConnectionInternal.removeParticipantsWithResponseAsync(callConnectionId, request,
393-
removeParticipantsOptions.getRepeatabilityHeaders().getRepeatabilityRequestId(),
394-
removeParticipantsOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat(),
379+
removeParticipantsOptions.getRepeatabilityHeaders() != null ? removeParticipantsOptions.getRepeatabilityHeaders().getRepeatabilityRequestId() : null,
380+
removeParticipantsOptions.getRepeatabilityHeaders() != null ? removeParticipantsOptions.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat() : null,
395381
context)
396382
.onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create)
397383
.map(response -> new SimpleResponse<>(response, RemoveParticipantsResponseConstructorProxy.create(response.getValue())));
@@ -411,4 +397,15 @@ public CallMediaAsync getCallMediaAsync() {
411397
return new CallMediaAsync(callConnectionId, contentsInternal);
412398
}
413399
//endregion
400+
401+
//region helper functions
402+
/***
403+
* Make sure repeatability headers of the request are correctly set.
404+
*
405+
* @return a verified RepeatabilityHeaders object.
406+
*/
407+
private RepeatabilityHeaders handleApiIdempotency(RepeatabilityHeaders repeatabilityHeaders) {
408+
return CallAutomationAsyncClient.handleApiIdempotency(repeatabilityHeaders);
409+
}
410+
//endregion
414411
}

sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallRecordingAsync.java

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,10 @@
5252
import java.nio.file.Path;
5353
import java.nio.file.StandardOpenOption;
5454
import java.security.InvalidParameterException;
55-
import java.time.Instant;
5655
import java.util.HashSet;
5756
import java.util.List;
5857
import java.util.Objects;
5958
import java.util.Set;
60-
import java.util.UUID;
6159
import java.util.stream.Collectors;
6260

6361
import static com.azure.core.util.FluxUtil.monoError;
@@ -123,18 +121,15 @@ Mono<Response<RecordingStateResult>> startRecordingWithResponseInternal(StartRec
123121
}
124122
StartCallRecordingRequestInternal request = getStartCallRecordingRequest(options);
125123

126-
if (options.getRepeatabilityHeaders() == null) {
127-
RepeatabilityHeaders autoRepeatabilityHeaders = new RepeatabilityHeaders(UUID.randomUUID(), Instant.now());
128-
options.setRepeatabilityHeaders(autoRepeatabilityHeaders);
129-
}
124+
options.setRepeatabilityHeaders(handleApiIdempotency(options.getRepeatabilityHeaders()));
130125

131126
return withContext(contextValue -> {
132127
contextValue = context == null ? contextValue : context;
133128
return contentsInternal
134129
.recordingWithResponseAsync(
135130
request,
136-
options.getRepeatabilityHeaders().getRepeatabilityRequestId(),
137-
options.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat(),
131+
options.getRepeatabilityHeaders() != null ? options.getRepeatabilityHeaders().getRepeatabilityRequestId() : null,
132+
options.getRepeatabilityHeaders() != null ? options.getRepeatabilityHeaders().getRepeatabilityFirstSentInHttpDateFormat() : null,
138133
contextValue)
139134
.onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create)
140135
.map(response ->
@@ -577,4 +572,15 @@ private URL getUrlToSignRequestWith(String endpoint) {
577572
throw logger.logExceptionAsError(new IllegalArgumentException(ex));
578573
}
579574
}
575+
576+
//region helper functions
577+
/***
578+
* Make sure repeatability headers of the request are correctly set.
579+
*
580+
* @return a verified RepeatabilityHeaders object.
581+
*/
582+
private RepeatabilityHeaders handleApiIdempotency(RepeatabilityHeaders repeatabilityHeaders) {
583+
return CallAutomationAsyncClient.handleApiIdempotency(repeatabilityHeaders);
584+
}
585+
//endregion
580586
}

sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/AddParticipantsOptions.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
import com.azure.core.annotation.Fluent;
1010

1111
import java.time.Duration;
12+
import java.time.Instant;
1213
import java.util.List;
14+
import java.util.UUID;
1315

1416
/**
1517
* The options for adding participants.
@@ -50,6 +52,7 @@ public final class AddParticipantsOptions {
5052
*/
5153
public AddParticipantsOptions(List<CommunicationIdentifier> participants) {
5254
this.participants = participants;
55+
this.repeatabilityHeaders = new RepeatabilityHeaders(UUID.fromString("0-0-0-0-0"), Instant.MIN);
5356
}
5457

5558
/**

sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/AnswerCallOptions.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
import com.azure.core.annotation.Fluent;
77

8+
import java.time.Instant;
9+
import java.util.UUID;
10+
811
/**
912
* The options for creating a call.
1013
*/
@@ -39,6 +42,7 @@ public class AnswerCallOptions {
3942
public AnswerCallOptions(String incomingCallContext, String callbackUrl) {
4043
this.incomingCallContext = incomingCallContext;
4144
this.callbackUrl = callbackUrl;
45+
this.repeatabilityHeaders = new RepeatabilityHeaders(UUID.fromString("0-0-0-0-0"), Instant.MIN);
4246
}
4347

4448
/**

sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CreateCallOptions.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
import com.azure.communication.common.CommunicationIdentifier;
77
import com.azure.core.annotation.Fluent;
88

9+
import java.time.Instant;
910
import java.util.List;
11+
import java.util.UUID;
1012

1113
/**
1214
* The options for creating a call.
@@ -60,6 +62,7 @@ public CreateCallOptions(CommunicationIdentifier source, List<CommunicationIdent
6062
this.source = source;
6163
this.targets = targets;
6264
this.callbackUrl = callbackUrl;
65+
this.repeatabilityHeaders = new RepeatabilityHeaders(UUID.fromString("0-0-0-0-0"), Instant.MIN);
6366
}
6467

6568
/**

sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/HangUpOptions.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
import com.azure.core.annotation.Fluent;
77

8+
import java.time.Instant;
9+
import java.util.UUID;
10+
811
/**
912
* The options for creating a call.
1013
*/
@@ -27,6 +30,7 @@ public class HangUpOptions {
2730
*/
2831
public HangUpOptions(boolean isForEveryone) {
2932
this.isForEveryone = isForEveryone;
33+
this.repeatabilityHeaders = new RepeatabilityHeaders(UUID.fromString("0-0-0-0-0"), Instant.MIN);
3034
}
3135

3236
/**

sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RedirectCallOptions.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import com.azure.communication.common.CommunicationIdentifier;
77
import com.azure.core.annotation.Fluent;
88

9+
import java.time.Instant;
10+
import java.util.UUID;
11+
912
/**
1013
* The options for creating a call.
1114
*/
@@ -35,6 +38,7 @@ public class RedirectCallOptions {
3538
public RedirectCallOptions(String incomingCallContext, CommunicationIdentifier target) {
3639
this.incomingCallContext = incomingCallContext;
3740
this.target = target;
41+
this.repeatabilityHeaders = new RepeatabilityHeaders(UUID.fromString("0-0-0-0-0"), Instant.MIN);
3842
}
3943

4044
/**

0 commit comments

Comments
 (0)