Ayende @ Rahien

Refunds available at head office

Why does RemoteDatabsaeChanges has DisposeAsync, and other pro dev tips

The following piece of code is taken from the RavenDB’s RemoteDatabaseChanges class, which implements the client side behavior for the RavenDB Changes API:

image

As you can see, we are doing something really strange here, DisposeAsync().

The reason it is there is that we need to send a command to the server to tell it to disconnect the connection from its end. Sure, we can just abort the request from our end (in fact, we are doing that), but only after we have tried to get the server to do this.

Why are we doing this?

The answer is quite simple. We want good Fiddler support.

By sending the disconnect command, we ensure that the connection will be properly closed, and Fiddler can then show the content, like so:

Being able to look at those (even if only after the connection has been closed) is invaluable when doing diagnostics, debugging or just wanting to take a peek.

On the hand, if we weren’t doing this, we would get 502 or 504 errors from Fiddler, which is annoying and opaque. And that isn’t a good way to create a good feel for people trying out your products.

Tags:

Posted By: Ayende Rahien

Published at

Originally posted at

Comments

Moti
08/02/2012 10:14 AM by
Moti

DDD - Debug Driven Design

chadbr
08/02/2012 12:54 PM by
chadbr

Wouldn't the application throw an exception if this runs when the app is closing down?

Ayende Rahien
08/02/2012 12:56 PM by
Ayende Rahien

Chadbr, We are handling this.

Ken Egozi
08/02/2012 04:46 PM by
Ken Egozi

I really like the "making live services more debuggable" series you are running.

a couple of things though: 1. why new CompletedTask all the time? since all CompletedTasks are essentially the same you could be able to have a CompletedTask.Instance or something of sorts, if you're doing that a lot. 2. are you 100% sure that keyValuePair.Value will never be null there? connections might leak in that (perhaps remote) case

Ayende Rahien
08/02/2012 05:31 PM by
Ayende Rahien

Ken,

1) The cost of new object() is minimal.

2) No, the value is never null.

Ken Egozi
08/02/2012 05:43 PM by
Ken Egozi

Without looking at your code, I'd guess that CompletedTask will generate a TaskCompletionSource and set its value. A new TaskCompletionSource() is hardly equivalent to new object(). A Task Completion Source etc is hardly a simple object(). who knows what it is doing internally during the construction of the tcs.

e.g. Brad Wilson on http://bradwilson.typepad.com/blog/2012/04/tpl-and-servers-pt4.html

talks about the cost for TCS creations, and advocates re-using cached versions for Completed (and Cancelled) tasks

as for 2) are you absolutely certain that no-when in the future you'll be null-ing a value in that dictionary for some reason, causing a failure here that no test will catch? Dispose calls should be as safe as possible, especially in a highly concurrent server env.

Ayende Rahien
08/02/2012 06:21 PM by
Ayende Rahien

Ken, This code: var sw = Stopwatch.StartNew(); for (int i = 0; i < 1000 * 1000; i++) { var tcs = new TaskCompletionSource(); tcs.SetResult(null); } Console.WriteLine(sw.ElapsedMilliseconds);

Completes in less than 150 ms, so I think that we are good on that regard.

As for anyhow anywhen for the error, no. But I am pretty sure that there is a test that will catch it if it will happen.

Comments have been closed on this topic.