The duplicate device issue stems from insufficient concurrency controls in your bulk import configuration. Here’s the complete solution:
Bulk Import Upsert Configuration:
The API’s upsert mode needs explicit concurrency handling:
POST /iot/api/v2/devices/bulk
{
"devices": [...],
"mode": "upsert",
"concurrencyControl": "optimistic",
"conflictResolution": "merge",
"validateUnique": true
}
Key parameters:
concurrencyControl: optimistic enables version-based conflict detection
conflictResolution: merge handles concurrent updates intelligently
validateUnique: true enforces pre-insert duplicate checking with proper locking
Duplicate Detection Logic:
Implement a two-phase import process:
Phase 1 - Pre-validation:
POST /iot/api/v2/devices/validate
{
"deviceIds": ["DEV-001", "DEV-002", ...],
"checkExisting": true
}
This returns which devices already exist, allowing you to separate inserts from updates.
Phase 2 - Targeted import:
Split your bulk operation into separate insert and update batches based on validation results. This eliminates the race condition by avoiding upsert logic entirely for known devices.
Device ID Validation:
Enable strict validation mode in the bulk import configuration:
bulkImport.validation.strict=true
bulkImport.validation.duplicateCheck=PESSIMISTIC
bulkImport.concurrency.lockTimeout=30000
The PESSIMISTIC duplicate check acquires row-level locks before checking existence, preventing the race condition. The lock timeout ensures operations don’t hang indefinitely.
Pre-Import Reconciliation:
Implement a reconciliation service that runs before bulk imports:
- Query existing devices matching the import payload deviceIds
- Classify each device as NEW, EXISTING_UNCHANGED, or EXISTING_MODIFIED
- Filter out EXISTING_UNCHANGED devices from the import
- Use INSERT for NEW devices and UPDATE for EXISTING_MODIFIED
- Submit separate bulk operations for inserts vs updates
This approach eliminates upsert ambiguity and prevents duplicates by making explicit insert/update decisions before API calls.
Concurrent Operation Handling:
If you must support truly concurrent bulk imports, implement distributed locking:
bulkImport.distributedLock.enabled=true
bulkImport.distributedLock.provider=REDIS
bulkImport.distributedLock.keyPrefix=device_import
This ensures only one bulk import operation processes any given deviceId at a time, even across multiple application instances.
Implementation Priority:
- Enable strict validation and pessimistic duplicate checking (immediate fix)
- Implement pre-import reconciliation service (prevents 95% of duplicates)
- Configure distributed locking for remaining edge cases
- Add monitoring to detect and alert on any duplicate creation
After implementing these controls, your bulk import operations will handle concurrency correctly without creating duplicates. The key is moving duplicate detection from application logic to database-level constraints with proper locking, combined with pre-validation that eliminates ambiguous upsert scenarios.