I'm having issues with proper handling of exceptions thrown from pipeline steps created using Open.ChannelExtensions library. In some scenarios exception is being swallowed instead of being propagated to caller.
From my observations, it seems that it's somehow related to the .Batch() step, also moment of throwing exceptions may have some meaning.
Am I doing something wrong? How it should be properly handled to propagate exception up?
// See https://aka.ms/new-console-template for more information
using System.Threading.Channels;
using Open.ChannelExtensions;
var test = new Test();
try
{
//await test.Scenario1(); //exception catched
//await test.Scenario2(); //exception swallowed
//await test.Scenario3(); //exception catched
//await test.Scenario4(); //exception sometimes catched (~25% chance)
}
catch (Exception)
{
Console.WriteLine("Got exception");
}
class Test
{
public async Task Scenario1()
{
var channel = Channel.CreateBounded<int>(10000);
for (int i = 0; i < 100; i++)
{
await channel.Writer.WriteAsync(i);
}
var task = channel.Reader.Pipe(1, (element) =>
{
throw new Exception();
Console.WriteLine(element);
return 1;
})
.Pipe(2, (evt) =>
{
Console.WriteLine("\t" + evt);
return evt * 2;
})
//.Batch(20)
.PipeAsync(1, async (evt) =>
{
Console.WriteLine("\t\t" + evt);
return Task.FromResult(evt);
})
.ReadAll(task =>
{
});
channel.Writer.TryComplete();
await task;
Console.WriteLine("end");
}
public async Task Scenario2()
{
var channel = Channel.CreateBounded<int>(10000);
for (int i = 0; i < 100; i++)
{
await channel.Writer.WriteAsync(i);
}
var task = channel.Reader.Pipe(1, (element) =>
{
throw new Exception();
Console.WriteLine(element);
return 1;
})
.Pipe(2, (evt) =>
{
Console.WriteLine("\t" + evt);
return evt * 2;
})
.Batch(20)
.PipeAsync(1, async (evt) =>
{
Console.WriteLine("\t\t" + evt);
return Task.FromResult(evt);
})
.ReadAll(task =>
{
});
channel.Writer.TryComplete();
await task;
}
public async Task Scenario3()
{
var channel = Channel.CreateBounded<int>(10000);
for (int i = 0; i < 100; i++)
{
await channel.Writer.WriteAsync(i);
}
var task = channel.Reader.Pipe(1, (element) =>
{
if(element == 20)
throw new Exception();
Console.WriteLine(element);
return 1;
})
.Pipe(2, (evt) =>
{
Console.WriteLine("\t" + evt);
return evt * 2;
})
//.Batch(20)
.PipeAsync(1, async (evt) =>
{
Console.WriteLine("\t\t" + evt);
return Task.FromResult(evt);
})
.ReadAll(task =>
{
});
channel.Writer.TryComplete();
await task;
}
public async Task Scenario4()
{
var channel = Channel.CreateBounded<int>(10000);
for (int i = 0; i < 100; i++)
{
await channel.Writer.WriteAsync(i);
}
var task = channel.Reader.Pipe(1, (element) =>
{
if (element == 20)
throw new Exception();
Console.WriteLine(element);
return 1;
})
.Pipe(2, (evt) =>
{
Console.WriteLine("\t" + evt);
return evt * 2;
})
.Batch(20)
.PipeAsync(1, async (evt) =>
{
Console.WriteLine("\t\t" + evt);
return Task.FromResult(evt);
})
.ReadAll(task =>
{
});
channel.Writer.TryComplete();
await task;
}
}