We’re integrating with Oracle Fusion Cloud SCM 23c manufacturing planning REST API to update Bill of Materials (BOM) structures. When multiple users or processes try to update the same BOM simultaneously, we get HTTP 409 Conflict errors and the updates fail.
Our update request:
PATCH /fscmRestApi/resources/11.13.18.05/bills/{billId}
{
"ComponentItem": "COMP-456",
"Quantity": 5
}
Error response:
409 Conflict
{"title": "The resource has been modified",
"detail": "Another user has updated this record"}
This happens frequently in our environment where engineering and planning teams both make BOM changes. The workflow gets blocked because failed updates need manual intervention. How do we handle concurrent BOM modifications properly? Is there a locking mechanism or retry strategy we should implement?
For manufacturing BOMs specifically, you should also consider using the BOM change order workflow if you need coordinated updates. Change orders provide a structured way to manage concurrent modifications with approval workflows. The REST API supports creating and managing change orders, which gives you better control over who can modify BOMs and when. This might be more appropriate than trying to handle conflicts at the API level if you have multiple teams making changes.
The 409 Conflict is Oracle’s optimistic locking mechanism preventing data corruption from concurrent updates. You need to implement ETag-based concurrency control. Before updating, GET the BOM to retrieve its current ETag value, then include that ETag in your PATCH request using the If-Match header. If someone else modified the BOM in the meantime, you’ll still get 409, but you can then retry with the updated ETag.
Let me provide a comprehensive solution covering all three focus areas for handling concurrent BOM updates:
Optimistic Locking:
Oracle Fusion uses optimistic locking for all manufacturing plan resources including BOMs. This prevents data corruption but requires proper handling in your integration. The mechanism works through ETags - each resource version has a unique ETag identifier.
ETag and If-Match Usage:
Implement this pattern for all BOM updates:
// Step 1: GET current BOM and capture ETag
Response getResponse = client.get("/bills/" + billId);
String etag = getResponse.getHeader("ETag");
JsonObject currentBOM = getResponse.getBody();
// Step 2: Merge your changes with current data
currentBOM.put("Quantity", newQuantity);
// Step 3: PATCH with If-Match header
Response patchResponse = client.patch("/bills/" + billId)
.header("If-Match", etag)
.body(currentBOM)
.execute();
The If-Match header tells Oracle “only apply this update if the current ETag matches.” If another process updated the BOM between your GET and PATCH, the ETags won’t match and you’ll get 409.
Concurrent Update Handling:
Implement intelligent retry logic with exponential backoff:
int maxRetries = 5;
int retryCount = 0;
boolean success = false;
while (!success && retryCount < maxRetries) {
try {
// GET-PATCH sequence from above
success = true;
} catch (HTTP409Exception e) {
retryCount++;
if (retryCount < maxRetries) {
Thread.sleep((long) Math.pow(2, retryCount) * 1000);
// Retry with fresh GET to get new ETag
} else {
// Log conflict and alert for manual resolution
throw new ConcurrentUpdateException("BOM update failed after " + maxRetries + " attempts");
}
}
}
Additional Best Practices:
-
Minimize GET-PATCH window: Keep the time between GET and PATCH as short as possible. Don’t do complex calculations or wait for user input between these calls.
-
Merge intelligently: When you retry after 409, don’t blindly overwrite with your original values. Fetch the latest version and merge your changes with any updates that were made by others. For example, if you’re updating quantity and someone else updated lead time, preserve their lead time change.
-
Use PATCH, not PUT: PATCH allows partial updates, reducing the chance of conflicts. PUT requires the entire resource and is more likely to conflict with concurrent modifications.
-
Implement update queuing: For high-conflict scenarios, implement a queue system where BOM updates are processed sequentially rather than concurrently. This eliminates conflicts entirely but adds latency.
-
Monitor conflict rates: Log all 409 responses and track conflict frequency. If you’re seeing >10% conflict rate, you have a process design issue that needs architectural changes (like the change order workflow Rachel mentioned).
-
Consider change orders for coordinated updates: For planned modifications involving multiple teams, use BOM change orders through the REST API. This provides workflow-based coordination and eliminates ad-hoc concurrent updates.
The retry logic with exponential backoff should resolve most conflicts within 2-3 attempts. If you consistently hit 5 retries, investigate whether multiple automated processes are hammering the same BOMs, and consider implementing distributed locking or update serialization at your application layer.
We faced this exact issue with manufacturing APIs. The key is understanding that Oracle uses ETags for optimistic locking on all manufacturing plan resources. Every GET response includes an ETag header representing the resource version. When you PATCH, you must include the If-Match header with that ETag. If the ETag doesn’t match the current server version, you get 409. Implement a GET-before-PATCH pattern in your code, and add retry logic that fetches the latest version on conflict.
There’s no exclusive locking mechanism in the REST API - optimistic locking with ETags is the only concurrency control. For retries, implement exponential backoff with a maximum of 3-5 attempts. Most conflicts resolve within 2-3 retries. If you’re seeing frequent conflicts, you might have a process design issue. Consider batching BOM updates or implementing a queue system where updates are serialized rather than concurrent. Also check if you can coordinate update timing between engineering and planning teams to reduce overlap.
Thanks for the ETag explanation. I’ve implemented the GET-before-PATCH pattern, but now I’m concerned about the race condition between GET and PATCH. If another user updates the BOM in that window, I still get 409. How many retries are reasonable before giving up? And is there a way to lock the BOM for exclusive updates during critical operations?