-
Notifications
You must be signed in to change notification settings - Fork 147
Open
Description
I'm trying to prevent duplicate entity creation when retrying failed requests due to transient issues like timeouts. I understand that a timeout may result in the client retrying the request, which could inadvertently create duplicate records.
I came across the RequestId property in ServiceContext and started experimenting to see if it could help ensure idempotency. Here's what I tested:
- I created a ServiceContext and assigned a unique RequestId to it.
- I created an Invoice and added it using DataService.Add().
- Then, I created a Payment linked to that invoice and called DataService.Add(payment) twice, using the same RequestId.
Result: Two identical payments were created. No error or warning was thrown.
Next, I tried using a Batch:
- I set the same RequestId in the ServiceContext.
- I created a new batch with dataService.CreateNewBatch(), added the same Payment once, and called Batch.Execute() twice.
Again, the result was two identical payments created.
So based on these tests, it seems like setting RequestId in ServiceContext does not prevent duplicate operations during retries.
Is there something I’m missing, or is RequestId not actually used by the QuickBooks Online API/SDK to ensure idempotency for these kinds of operations?
Here’s the relevant code for context:
Invoice invoice = new()
{
DocNumber = $"POS-a520-6e27de50cdпf",
CustomerRef = new ReferenceType { Value = "1", name = "Adwin Ko" },
TxnDate = new DateTime(2025, 4, 10),
DueDate = new DateTime(2025, 4, 10),
DueDateSpecified = true,
TxnTaxDetail = new TxnTaxDetail
{
TotalTax = Convert.ToDecimal(10),
TotalTaxSpecified = true
},
Line = new[]
{
new Line
{
Description = "Description",
Amount = 100,
AmountSpecified = true,
DetailType = LineDetailTypeEnum.DescriptionOnly,
DetailTypeSpecified = true,
}
}
};
DataService dataService = new(_serviceContext);
Invoice createdInvoice = dataService.Add(invoice);
var payment = new Payment
{
CustomerRef = new ReferenceType { Value = "1" },
TotalAmt = 10,
TotalAmtSpecified = true,
TxnDate = DateTime.UtcNow,
PrivateNote = "POS-a520-6e27de50cdgg",
PaymentRefNum = "POS-a520-6e27de50cdgg",
Line = new[]
{
new Line
{
Amount = 10,
AmountSpecified = true,
LinkedTxn = new[]
{
new LinkedTxn
{
TxnId = createdInvoice.Id,
TxnType = "Invoice"
}
}
}
}
};
_serviceContext.RequestId = Guid.NewGuid().ToString();
// Direct call (duplicated)
dataService.Add(payment);
dataService.Add(payment);
// Using Batch (duplicated)
Batch batch = dataService.CreateNewBatch();
batch.Add(payment, "id", OperationEnum.create);
batch.Execute();
batch.Execute();
Metadata
Metadata
Assignees
Labels
No labels