Skip to content

Improper/missing IAsyncEnumerator disposal? #905

Description

@InspiringCode

Excel Type

  • XLSX

MiniExcel Version

1.42.0

Description

When calling SaveAsAsync multiple times sequentially, it seems that the IAsyncEnumerator is not disposed correctly. I have the following code:

List<IAsyncEnumerable<T>> partitions = [];

int i = 0;
while (i < totalAmountExcelFiles)
{
    partitions.Add(query.Skip(i * maxRowsPerFile).Take(maxRowsPerFile).AsAsyncEnumerable());
    i++;
}

int j = 1;
using var zip = new ZipArchive(target, ZipArchiveMode.Create, leaveOpen: true);
foreach (IAsyncEnumerable<T> partition in partitions)
{
    var entry = zip.CreateEntry($"{fileNameTemplate}_{j++:D2}.xlsx", CompressionLevel.Optimal);

    await using (Stream entryStream = entry.Open())
    {
        await MiniExcel.SaveAsAsync(entryStream, partition, cancellationToken: ct);
        await entryStream.FlushAsync(ct);
    }
}

When executing it throws an Npgsql.NpgsqlOperationInProgressException ("(0x80004005): A command is already in progress") on the second iteration with the callstack:

   at Npgsql.ThrowHelper.ThrowNpgsqlOperationInProgressException(NpgsqlCommand command)
   at Npgsql.Internal.NpgsqlConnector.<StartUserAction>g__DoStartUserAction|282_0(ConnectorState newState, NpgsqlCommand command, CancellationToken cancellationToken, Boolean attemptPgCancellation)
   at Npgsql.Internal.NpgsqlConnector.StartUserAction(ConnectorState newState, NpgsqlCommand command, CancellationToken cancellationToken, Boolean attemptPgCancellation)
   at Npgsql.NpgsqlCommand.<ExecuteReader>d__120.MoveNext()
   at Npgsql.NpgsqlCommand.<ExecuteReader>d__120.MoveNext()
   at Npgsql.NpgsqlCommand.<ExecuteDbDataReaderAsync>d__113.MoveNext()
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.<ExecuteReaderAsync>d__18.MoveNext()
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.<ExecuteReaderAsync>d__18.MoveNext()
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.<InitializeReaderAsync>d__21.MoveNext()
   at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.<ExecuteAsync>d__7`2.MoveNext()
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.<MoveNextAsync>d__20.MoveNext()
   at System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
   at MiniExcelLibs.WriteAdapter.AsyncEnumerableWriteAdapter`1.<GetRowsAsync>d__6.MoveNext()
   at MiniExcelLibs.WriteAdapter.AsyncEnumerableWriteAdapter`1.<GetRowsAsync>d__6.System.Threading.Tasks.Sources.IValueTaskSource<System.Boolean>.GetResult(Int16 token)
   at MiniExcelLibs.OpenXml.ExcelOpenXmlSheetWriter.<WriteValuesAsync>d__7.MoveNext()
   at MiniExcelLibs.OpenXml.ExcelOpenXmlSheetWriter.<WriteValuesAsync>d__7.MoveNext()
   at MiniExcelLibs.OpenXml.ExcelOpenXmlSheetWriter.<CreateSheetXmlAsync>d__3.MoveNext()
   at MiniExcelLibs.OpenXml.ExcelOpenXmlSheetWriter.<SaveAsAsync>d__0.MoveNext()
   at MiniExcelLibs.MiniExcel.<SaveAsAsync>d__3.MoveNext()

If I change the loop to a simple async enumeration:

int debug = 1;
foreach (IAsyncEnumerable<T> partition in partitions)
{
    var entry = zip.CreateEntry($"{fileNameTemplate}_{j++:D2}.xlsx", CompressionLevel.Optimal);

    await foreach (T item in partition)
        debug++;
}

it works without problems, so it seems that MiniExcel doesn't correctly dispose the IAsyncEnumerator.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions