Optimistic Concurrency Control in Distributed Systems for 3D Validation with AI

Your AI pipeline is processing hundreds of 3D models per hour. Geometric engines analyze meshes, and neural networks detect anomalies at an astonishing speed. The hardware is maxed out, and the cloud is billing thousands of dollars. But suddenly, latency times spike. The timeouts start flooding your logs.

The bottleneck? It's not the GPUs. It's not the bandwidth. It's your relational database drowning in locks while waiting for asynchronous processes to finish modifying model state.

In distributed architectures focused on processing heavy assets (such as 3D model validation using AI), state management is the ultimate challenge. If you have already structured your solution by isolating the AI from the core business logic—as we saw in the article on Clean Architecture applied to 3D systems—the next evolutionary step is mastering how these asynchronous components compete to write to your database.

The Dilemma: Pessimistic Locking vs. Optimistic Validation

Imagine a common use case:

  1. The AI Microservice finishes analyzing a model .glb and attempts to update its status to “Anomalies Detected”.
  2. Simultaneously, the Geometric Engine discovers that the mesh is not watertight and attempts to mark the same model as “Invalid”.
  3. A User (or supervising system) attempts to rename the asset from the dashboard.

How do we prevent the last request from overwriting critical changes from previous ones, losing valuable information?

The initial instinct of many developers is to use Pessimistic Concurrency (SELECT ... FOR UPDATE in SQL). The system locks the row in the database until the transaction completes.

In a traditional system (e.g., a basic CRUD), this works. In a generative AI and 3D validation system, it is a death sentence for scalability. 3D analysis and ML inference take time (often seconds or minutes). If you lock records in the main database while the AI is 'thinking' or while waiting for responses from asynchronous queues, you will exhaust your database connection pool, and the latency of the entire system will multiply.

The Solution: Optimistic Concurrency

Optimistic Concurrency Control (OCC) operates on a different premise: we assume collisions are rare. Instead of locking the database to prevent conflicts, we allow everyone to read freely and check for modifications only at the exact moment of saving.

If the record was altered by another process since we read it, the database rejects our update; we intercept that error, refresh the data, and (depending on the business rule) retry or abort.

The Mechanism: Entity Versioning

To achieve this, we added a version identifier to our domain entities. In SQL Server, this is classically done with a column RowVersion (or Timestamp), but it can also be implemented in an agnostic way with a simple integer Version or an Guid (ETag).

Practical Example in C# and .NET

Let's see how to implement a repository that handles optimistic concurrency elegantly, protecting our model MeshValidationJob.

// Entidad de Dominio
public class MeshValidationJob
{
    public Guid Id { get; private set; }
    public string Status { get; private set; }
    public string ValidationSummary { get; private set; }
    
    // El token de concurrencia
    public byte[] RowVersion { get; private set; } 

    public void MarkAsFailedByAI(string reason)
    {
        // Regla de negocio: Si ya estaba marcado como fallido por el motor geométrico, 
        // anexamos la razón en lugar de sobrescribirla.
        Status = "Failed";
        ValidationSummary = string.IsNullOrEmpty(ValidationSummary) 
            ? $"AI Error: {reason}" 
            : $"{ValidationSummary} | AI Error: {reason}";
    }
}

In the infrastructure, we configure Entity Framework Core to use RowVersion as the concurrency token:

// Configuración de EF Core
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<MeshValidationJob>()
        .Property(j => j.RowVersion)
        .IsRowVersion(); // Habilita la comprobación optimista
}

And finally, in our Use Case (Application Layer), we handle the inevitable conflict (the DbUpdateConcurrencyException exception):

public class UpdateAiValidationResultUseCase
{
    private readonly ApplicationDbContext _dbContext;

    public UpdateAiValidationResultUseCase(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task ExecuteAsync(Guid jobId, string aiErrorReason)
    {
        bool saveFailed;
        do
        {
            saveFailed = false;
            
            // 1. Lectura sucia y rápida (Sin bloqueos)
            var job = await _dbContext.ValidationJobs.FindAsync(jobId);
            if (job == null) throw new Exception("Job not found.");

            // 2. Modificación en memoria
            job.MarkAsFailedByAI(aiErrorReason);

            try
            {
                // 3. Intento de guardado. EF Core automáticamente añade: 
                // WHERE Id = @id AND RowVersion = @rowVersionLeida
                await _dbContext.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException ex)
            {
                saveFailed = true;

                // ¡Conflicto detectado! Otro proceso (ej. el Motor Geométrico) modificó este Job.
                // Refrescamos los valores de la base de datos (resolución 'Client Wins' o merge)
                var entry = ex.Entries.Single();
                var databaseValues = await entry.GetDatabaseValuesAsync();
                
                if (databaseValues == null)
                {
                    throw new Exception("El Job fue eliminado por otro proceso.");
                }

                // Sobrescribimos los valores originales con los de la BD para el reintento
                entry.OriginalValues.SetValues(databaseValues);
            }

        } while (saveFailed); // Reintentamos hasta que tengamos éxito
    }
}

In this code, our system never blocks the database. If two processes collide, the loser recalculates its logic in milliseconds and retries. The database breathes easy.

Direct Business Impact (P&L)

Architecture is not just code; it is economics. Implementing Optimistic Concurrency in heavy AI pipelines has immediate and measurable effects:

  1. Throughput Multiplication: By eliminating the lock from the database, you can scale your 3D processing workers horizontally without the database becoming a bottleneck. You validate more models per hour with the same infrastructure.
  2. Reducing Compute Costs: Database instances handling fewer blocked transactions require less CPU and memory. You can use a more economical tier from your Cloud provider.
  3. Guaranteed Integrity: You will never again lose a critical failure report from your Geometry Engine because an asynchronous AI worker blindly overwrote the row.

Conclusion

In distributed systems where AI and heavy processing coexist, embracing the asynchronous and optimistic nature of the real world is not optional; it is the only path to high performance.

Optimistic concurrency control, combined with a decoupled architecture, transforms a fragile system into a predictable industrial machine.

Is your platform suffering from inexplicable bottlenecks or data integrity issues when scaling? Concurrency and architecture problems are rarely solved by adding more servers. If you need to unlock your B2B infrastructure's performance, schedule a free call with me and let's design a backend that can keep up with your business.