Skip to content

Improper/missing IAsyncEnumerator disposal? #905

@InspiringCode

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions