After spending the last 5 years deep in networking code, I can say one of the most fundamental missing pieces is the ability to know why a connection closed (root causing the problem).
I wish all the protocols from here on out would also have a "reason for close" field for additional debugging information. The cumulative time that has been lost trying to debug what part of the stack caused the connection to drop (OS, proxy, libraries) probably adds up to years.
This gets even more complicated by these "invisible layers" introduced by virtualization. Cloud networking comes to mind... don't forget the layers built on top of that in orchestrators like kubernetes.
What we need is a way to root cause where these issues come from by adding the ability to shuttle more information in these packets. Or maybe these should be ignored and everything should just be retrying forever 😅
• • •
Missing some Tweet in this thread? You can try to
force a refresh
How is it different from SignalR you ask? Well internally it's built on the same underlying tech but the big difference is that there's no client requirement or protocol requirement, BYOWL (bring your own websocket library).
The mainline scenarios are also focused on severless so we can handle your long running websocket connections and trigger HTTP calls to any backend. It can be azure functions or any addressable HTTP endpoint!
The transition to asynchronous code changes a lot of the basics we're used to. There's usually much more concurrency in these systems and that becomes more challenging to diagnose when things go wrong. #dotnet#aspnetcore
The threads are usually switching between lots of concurrent operations as various IO operations complete. Here's an example of visualizing lots of concurrent operations happening in the parallel tasks window. The right is parallel stacks. Async stacks vs OS thread stacks.
Essentially the async logical stacks are linked lists of objects stored on the heap. There may not be any code executing if a request is waiting on IO for example.
4 months I got to spend time with friends and family. We went on cruises, and had lots of beach days. The kids learned how to swim at the beach. They got to live with grandparents for 3 of those 4 months. Got to spend my birthday here for the first time in over 10 years.
Got to experience what it would be like to work remotely from Barbados. Started a relationship between Microsoft and the UWI (University of the West Indies). Joined a WhatsApp group of coders of Barbados and am doing what I can to make them love .NET 🤣.
.NET APIs you didn't know existed. StringBuilder.GetChunks docs.microsoft.com/en-us/dotnet/a…. You can use this API to get access to the internal buffer of the StringBuilder instead of turning it into a String. #dotnet
StringSplitOptions.TrimEntries docs.microsoft.com/en-us/dotnet/a…. Ever split a string and didn't want to trim each entry? Me too, now you can use this enum to do it!
There are some common issues I see when people use ConcurrentDictionary:
- Dealing with the fact that GetOrAdd executes the creation callback more than once. This means if you create something expensive, it'll happen more than once. (this is documented) #dotnet
- If you create a disposable object in your factory and it gets called multiple times, the created objects will never be disposed.
- Making sure asynchronous factories and are called once. (making all callers wait on the same value).
Here's a contrived example of the resource leak. The code runs a couple of concurrent operations and uses GetOrAdd to cache a FileStream. This will call File.OpenRead potentially multiple times which will result in opening a handle to the resource and not disposing it.
Week 2 of analyzing how goroutines pause and resume and how the networking stack and other subsystems interact with the primitives exposed by the runtime.
One of the things I appreciate about C# is how many low level features are directly exposed to users. #golang#dotnet
In golang, it's not possible for you to implement pausing and resuming of goroutines other than by using the primitives go offers, channels, network IO, timers (sleep). This is fine for most applications but comes with additional overhead.
I also learned that go's GC doesn't move pointers and therefore there's no way to pin memory when working with C interop. There's no equivalent to passing around a GCHandle in go, just don't pass things with managed pointers to C.