dotnet / reactive

The Reactive Extensions for .NET
http://reactivex.io
MIT License
6.73k stars 751 forks source link

Throttle breaks the observable chain while running on wasm in .net 8 #2082

Open aldelaro5 opened 9 months ago

aldelaro5 commented 9 months ago

Bug

Which library version? 6.0.0 and 5.0.0 has the issue

What are the platform(s), environment(s) and related component version(s)? .net 8, avalonia 11.0.9 using wasm and DynamicData 7.9.5 (but I tried 8.3.27 and same result)

What is the use case or problem? If I call Throttle while this avalonia app is running under wasm in .net 8, it breaks the observable chain and no data can be seen while it shows on desktop or if I comment out the Throttle call or if I downgrade to .net 7.

What is the expected outcome? To match the behavior on the desktop version and .net 7

What is the actual outcome? No data can be seen on the wasm version of this avalonia project while they are seen on the desktop version. Data can also be seen on both versions if I downgrade to .net 7.

What is the stacktrace of the exception(s) if any? None, no exception seems to be thrown.

Do you have a code snippet or project that reproduces the problem? Yes, this issue contains a zip with a minimal Avalonia project using Rx.net via DynamicData.

AvaloniaApplication2.zip

idg10 commented 9 months ago

I'm not confident I know what this means:

it breaks the observable chain

Looking at your code, it appears that this:

private readonly List<Stuff> _backingList= new(Enumerable.Repeat(new Stuff(), 10).ToList());

produces a fixed-size (10 entry) list of Stuff instances, each of which looks like this:

public partial class Stuff : ObservableObject

    [ObservableProperty]
    private int _thing = Random.Shared.Next();
}

which appears to pick a random number during construction.

None of these things appears to change, so I'm not sure what dynamic observable behaviour you're expecting. If there are no changes, what is there to observe?

I tried running your app. The desktop one shows the same number 10 times over in a list, which wasn't quite what I expected. And the Browser one was unable to get as far as showing anything at all. It just sits there with a browser page showing about:blank, and then after a while shows this:

Failed to launch debug adapter.  Additional information may be available in the output window.

Unable to launch browser: "Could not open wss://localhost:5001/debug?browser=wsAFF127.0.0.1A49289FdevtoolsFbrowserFf1eb29a5-bd1d-4a43-941b-eebd23f7b450"

I got that error both with and without the call to Throttle.

So I'm going to have to guess what problem you're seeing since the browser app in your repro won't start on my machine, and I don't understand what "breaks the observable chain" means.

I'm going to guess that you mean that the observable stops working—that you don't get data appearing in the display.

It's possible that this is connected to #2061 which caused by the fact that the default schedulers don't currently work very well on Blazor Wasm because there are many situations in which they attempt to create threads, which you're not allowed to do in that runtime environment.

Currently we have no way to run tests in Blazor Wasm because there seems to be no support for doing that - https://github.com/microsoft/testfx/issues/2196

We intend to improve support for wasm in the browser as soon as possible, but the inability to run automated tests makes it tricky for now.

aldelaro5 commented 9 months ago

I'm not confident I know what this means:

it breaks the observable chain

Looking at your code, it appears that this:

private readonly List<Stuff> _backingList= new(Enumerable.Repeat(new Stuff(), 10).ToList());

produces a fixed-size (10 entry) list of Stuff instances, each of which looks like this:

public partial class Stuff : ObservableObject

    [ObservableProperty]
    private int _thing = Random.Shared.Next();
}

which appears to pick a random number during construction.

None of these things appears to change, so I'm not sure what dynamic observable behaviour you're expecting. If there are no changes, what is there to observe?

I tried running your app. The desktop one shows the same number 10 times over in a list, which wasn't quite what I expected. And the Browser one was unable to get as far as showing anything at all. It just sits there with a browser page showing about:blank, and then after a while shows this:

Failed to launch debug adapter.  Additional information may be available in the output window.

Unable to launch browser: "Could not open wss://localhost:5001/debug?browser=wsAFF127.0.0.1A49289FdevtoolsFbrowserFf1eb29a5-bd1d-4a43-941b-eebd23f7b450"

I got that error both with and without the call to Throttle.

So I'm going to have to guess what problem you're seeing since the browser app in your repro won't start on my machine, and I don't understand what "breaks the observable chain" means.

I'm going to guess that you mean that the observable stops working—that you don't get data appearing in the display.

It's possible that this is connected to #2061 which caused by the fact that the default schedulers don't currently work very well on Blazor Wasm because there are many situations in which they attempt to create threads, which you're not allowed to do in that runtime environment.

Currently we have no way to run tests in Blazor Wasm because there seems to be no support for doing that - microsoft/testfx#2196

We intend to improve support for wasm in the browser as soon as possible, but the inability to run automated tests makes it tricky for now.

Sorry for the ambiguity, let me clarify.

What I mean by it breaks the chain is indeed that no data appears in the display. They exist, removing the Throttle call shows them on wasm, but it completely wipes them out if I leave throttle in.

As for why you cannot launch the debugger, I don't know. I am using Rider and f5 debugging appears to work with chrome, but it is limited. You can repro the issue with a simple run without debugging, but I am not sure why it didn't launch on your end.

As for the setup to repro the issue, it's mostly a minimal example to have some kind of data to isolate the problem that it's throttle that causes the issue. I normally got this from a much more complex project, but I thought that it was too complex for an issue report so I made the most basic version I could think of that repro the issue in a new project.

There is one thing I am perplexed on: this doesn't reproduce if I downgrade the project to .net 7. It means somehow, .net 8 specifically is involved, but it's not clear why that would be. Is there anything that comes to mind on what could have changed?

akarnokd commented 9 months ago

Maybe you need ToObservableChangeSet instead of AsObservableChangeSet?

Source: https://stackoverflow.com/a/72542353/61158

aldelaro5 commented 9 months ago

Maybe you need ToObservableChangeSet instead of AsObservableChangeSet?

Source: https://stackoverflow.com/a/72542353/61158

This doesn't behave the same and it doesn't acomplish the same thing.

Besides, I don't know why it would have to do with this issue because other methods from DynamicData or Rx works just fine (I could even get a text filter to work).

idg10 commented 9 months ago

I've now tried it in Rider, and am able to run the Blazor app and repro the problem. However, Rider seems entirely unable to step into Rx source code when debugging a Blazor app.

I've enabled external source debugging, and it works fine if I run the desktop app in your repro—with that, I can set a breakpoint inside Rx.NET's DefaultScheduler and watch what how Throttle operator is using that. But when I switch to the Blazor app, this all stops working.

I've found that Visual Studio also seems to have a bunch of similar problems when debugging Blazor apps, so I guess there are debug limitations with .NET on Browser WASM.

So far I have very little experience with .NET Browser WASM development. Perhaps there's something simple I'm missing, because as far as I can tell, I can't to set breakpoints inside NuGet libraries for a Blazor app. I can't even get the debugger to break in any time an exception is thrown (something that appears not to work for me on Blazor apps in general, not just with this app). I can't even get the IDE to tell me that an exception has been thrown! (As far as I can see, Blazor apps don't get the normal messages that the Debug Output window would typically show each time an exception is thrown.) If someone can point me at anything that would help with any of these blockers, that would be really handy, because right now, the debugger is making it more or less impossible for me to look into this in any meaningful way.

But failing that, I think what I'll probably need to do is open up the main Rx.NET repo and add a Blazor project to that, in the hope that it will then let me single-step through the Rx source code (because I won't be using it via NuGet in that case - it'll be a project reference). Right now I've got some other work in progress for Rx, so it might be a while before I can get to this.

Unfortunately, until such time as it's possible for us to run unit tests in Browser Wasm, we can't meaningfully offer support for that environment, so although I'm going to try to work out what's happening here, we just have to say that we don't properly support Blazor today.

if I downgrade the project to .net 7. It means somehow, .net 8 specifically is involved, but it's not clear why that would be. Is there anything that comes to mind on what could have changed?

.NET's WASM support is evolving quite quickly at the moment, so a lot of things will have changed from .NET 7 to .NET 8, making it very hard to guess which particular change might be at the root of this.