/// <summary> /// Add a new item to the database /// </summary> /// <param name="fileIndexItem">the item</param> /// <returns>item with id</returns> public virtual async Task <FileIndexItem> AddItemAsync(FileIndexItem fileIndexItem) { async Task <FileIndexItem> LocalDefaultQuery() { var context = new InjectServiceScope(_scopeFactory).Context(); return(await LocalQuery(context)); } async Task <FileIndexItem> LocalQuery(ApplicationDbContext context) { // only in test case fileIndex is null if (context.FileIndex != null) { await context.FileIndex.AddAsync(fileIndexItem); } await context.SaveChangesAsync(); // Fix for: The instance of entity type 'Item' cannot be tracked because // another instance with the same key value for {'Id'} is already being tracked context.Entry(fileIndexItem).State = EntityState.Unchanged; AddCacheItem(fileIndexItem); return(fileIndexItem); } try { return(await LocalQuery(_context)); } catch (Microsoft.Data.Sqlite.SqliteException e) { _logger?.LogInformation(e, $"catch-ed SqliteException going to retry 2 times {fileIndexItem.FilePath}"); return(await RetryHelper.DoAsync( LocalDefaultQuery, TimeSpan.FromSeconds(2), 2)); } catch (DbUpdateException e) { _logger?.LogInformation(e, $"catch-ed DbUpdateException going to retry 2 times {fileIndexItem.FilePath}"); return(await RetryHelper.DoAsync( LocalDefaultQuery, TimeSpan.FromSeconds(2), 2)); } catch (ObjectDisposedException) { var context = new InjectServiceScope(_scopeFactory).Context(); return(await LocalQuery(context)); } }
/// <summary> /// Retry when an Exception has occured /// </summary> /// <param name="updateStatusContent"></param> /// <param name="e">Exception</param> private async Task RetrySaveChangesAsync(FileIndexItem updateStatusContent, Exception e) { _logger?.LogInformation(e, "[RetrySaveChangesAsync] retry catch-ed exception "); _logger?.LogInformation("[RetrySaveChangesAsync] next retry ~>"); async Task LocalRetrySaveChangesAsyncQuery() { // InvalidOperationException: A second operation started on this context before a previous operation completed. // https://go.microsoft.com/fwlink/?linkid=2097913 await Task.Delay(5); var context = new InjectServiceScope(_scopeFactory).Context(); context.Attach(updateStatusContent).State = EntityState.Modified; await context.SaveChangesAsync(); context.Attach(updateStatusContent).State = EntityState.Detached; await context.DisposeAsync(); } try { await LocalRetrySaveChangesAsyncQuery(); } catch (MySqlException mySqlException) { _logger?.LogError(mySqlException, "[RetrySaveChangesAsync] MySqlException catch-ed and retry again"); await LocalRetrySaveChangesAsyncQuery(); } catch (DbUpdateConcurrencyException concurrencyException) { SolveConcurrency.SolveConcurrencyExceptionLoop(concurrencyException.Entries); try { _logger?.LogInformation("[RetrySaveChangesAsync] SolveConcurrencyExceptionLoop disposed item"); var context = new InjectServiceScope(_scopeFactory).Context(); await context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException retry2Exception) { _logger?.LogInformation(retry2Exception, "[RetrySaveChangesAsync] save failed after DbUpdateConcurrencyException"); } } }