entity-framework-coreazure-functions.net-8.0

SQLite + Azure Functions: SQLite Error 5: database is locked


I have a .NET 8 Azure Functions application that uses a SQL Server to store information. I am trying to migrate over to SQLite to make data access faster and reduce costs. When I run the application locally, it works fine, however when it is deployed to Azure Functions, the following error occurs when I try to run a SELECT query:

2025-06-05T16:28:16Z   [Error]   An exception occurred while iterating over the results of a query for context type 'Infrastructure.Persistence.MLTrainingContext'.
Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'.
   at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
   at Microsoft.Data.Sqlite.SqliteCommand.PrepareAndEnumerateStatements()+MoveNext()
   at Microsoft.Data.Sqlite.SqliteCommand.GetStatements()+MoveNext()
   at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
   at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
   at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReader(CommandBehavior behavior)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.InitializeReader(Enumerator enumerator)
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.<>c.<MoveNext>b__21_0(DbContext _, Enumerator enumerator)
   at Microsoft.EntityFrameworkCore.Storage.NonRetryingExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()

The app I am using it the only one accessed the DbContext, or the database, and I have no concurrent functions running that would require the database to be accessed at the same time. Does anyone have any ideas as to why this occurs?

DbContext:

using Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;

namespace Infrastructure.Persistence
{
    public class MLTrainingContext : DbContext
    {
        public DbSet<Model> Models { get; set; }
        public DbSet<Library> Libraries { get; set; }
        public DbSet<DestinationRoutingRule> DestinationRoutingRules { get; set; }

        private readonly string _connString;

        public MLTrainingContext(DbContextOptions<MLTrainingContext> options) : base(options)
        {
            _connString = Utils.GetDBConnectionString();
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Model>().HasMany(m => m.Libraries)
                .WithMany(l => l.Models);
        }

        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
            options.UseSqlite(_connString,
            x => x.MigrationsAssembly("Infrastructure"));

            options.ConfigureWarnings(warnings =>
                warnings.Ignore(RelationalEventId.NonTransactionalMigrationOperationWarning));
        }

        public void Save()
        {
            lock (this)
            {
                SaveChanges();
            }
        }
    }
}

Solution

  • An exception occurred while iterating over the results of a query for context type 'Infrastructure.Persistence.MLTrainingContext'. Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'.

    Database is locked occurs if your application is experiencing more concurrency than SQLite can handle in default configuration.

    This error means that one thread or process has an exclusive lock on the database connection and another thread timed out waiting for the lock the be released.

    I agree with @Svyatoslav Danyliv, SQLite is a file-based database, it reads or writes directly to a file on the disk. Unlike SQL Server or PostgreSQL, it doesn't support high concurrency which can be problematic in Azure Functions.

    1. Even if you don’t explicitly trigger concurrency, Azure might scale out the function app leading to unintended concurrent access.

    2. File access is exclusive in SQLite. If one function instance is reading or writing, another instance cannot access it until the lock is released.

    3. Azure Function file systems with App Service Plan or Consumption Plan are not optimal for SQLite. The filesystem may be read-only or limited in concurrent access.

    Workaround:

    private static readonly object _dbLock = new();
    
    public void Save()
    {
      lock (_dbLock)
      {
        SaveChanges();
      }
    }
    
    {
      "version": "2.0",
      "concurrency": {
        "dynamicConcurrencyEnabled": false,
        "maximumFunctionConcurrency": 1
      }
    }