With Microsoft.Azure.DocumentDB 1.9.0 the ConnectionProtocol variable in the ConnectionPolicy has been made obsolete with the comment:
"This property is deprecated. Please use ConnectionMode to choose communication protocol in conjution with connection endpoint mode."
We still set it to Tcp, and we set ConnectionMode to Direct. However, when doing a Fiddler capture of our app I can see the requests going to DocumentDb over HTTPS.
How do I force the lib to use the Tcp connection? Do I have to change the endpoint string? Ours is currently of the form:
https://mydocumentdb.documents.azure.com:443
as that's what Azure tells us to use. I'm really not clear what the comment means by "connection endpoint mode".
EDIT: By request, here's my connection code:
DocumentDbConnection ConnectionData = new DocumentDbConnection();
ConnectionPolicy ClientConnectionPolicy = ConnectionPolicy.Default;
ClientConnectionPolicy.ConnectionMode = ConnectionMode.Direct;
ClientConnectionPolicy.ConnectionProtocol = Protocol.Tcp;
ConnectionData.DbClient = new DocumentClient( new Uri( DbEndpoint ), AccountKey, ClientConnectionPolicy );
// do initial connection upfront to avoid first-query latency
await ConnectionData.DbClient.OpenAsync();
DatabaseAccount DbAccount = await ConnectionData.DbClient.GetDatabaseAccountAsync();
Direct TCP mode is only supported for any requests for server resources(like Documents). Requests for master resources(like document collection) will still go through the Gateway.
Can you elaborate what kind of requests you are seeing in fiddler? Note that the client initialization related requests will also go through gateway and any subsequent requests for server resources will be directed using TCP.
Are you using partitioned collections feature?
Note that we brought back the ConnectionProtocol in .NET SDK 1.9.2(which was marked as Obsolete earlier). If you were setting the Protocol to TCP and Mode to Direct even earlier it should work as expected. No need to change the endpoint string.
Regards,
Rajesh
Related
As far as I know, in HTTP 1.1 you can use the same TCP/IP connection for multiple requests, but you can't execute more than one request at a time on that connection. In other words, it has to go like: Request, Response, Request, Response, Request, .... You can't do something like: Req1, Req2, Resp1, Req3, Resp3, Resp2. Maybe you can with HTTP/2, I don't know.
Anyway, my question is: what happens if you try to send multiple simultaneous requests with FlurlClient?
Like:
using (var client = new FlurlClient("https://api.com"))
{
var req1Task = client.Request("path1").PostJsonAsync(thing);
var req2Task = client.Request("path2").GetAsync();
await Task.WhenAll(req1Task, req2Task);
// Do something with responses.
}
I know the answer for HttpClient.
The answer is that if you try to start another request on HttpClient when a request is already pending, HttpClient will create a new TCP/IP connection. Whereas if you had waited until the first request was done, HttpClient would reuse the connection for the 2nd request.
My guess is that FlurlClient is the same.
Your assumption is correct about FlurlClient behaving the same as HttpClient in that regard. Flurl is just a thin abstraction layer on top of HttpClient, which is itself an abstraction on top of several more layers. Eventually you hit the platform-specific networking stack that actually implements the protocols.
It is valid and (usually) smart to have multiple calls happening concurrently like you've done in your example. Once connection limits are hit (which is adjustable via ServicePointManager), requests will simply queue up until a connection is available. Just be sure that number doesn't get too high or you'll likely start receiving errors from the server. Also, like HttpClient, be sure you're reusing a FlurlClient instance as much as possible so you don't run into this problem.
I need to send multiple async requests to a rest server through the same connection and get them executed in FIFO order, I think HTTP 1.1 pipelining is just perfect for this.
I found some related issues on Netty but I couldn't find much on their user guide and nothing on their test cases.
Is HTTP 1.1 pipelining supported on Netty? How would that be implemented?
An example would be greatly appreciated.
Related -unanswered- question: HTTP 1.1 pipelining vs HTTP 2 multiplexing
Since Netty is closer to the TCP layer, than to the HTTP layer, sending multiple requests is easy, after setting up the pipeline, just write them.
HttpRequest request1 = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/");
request1.headers().set(HttpHeaderNames.HOST, host);
request1.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
request1.headers().set(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP);
channel.writeAndFlush(request1);
HttpRequest request2 = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/");
request2.headers().set(HttpHeaderNames.HOST, host);
request2.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
request2.headers().set(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP);
channel.writeAndFlush(request2);
And then inside you channelRead method, read them in the same order you have send them.
To properly manage the queues for the packets, you could a solution like this, where you basicly keep a queue, so you know the correct callback to call after a request completes.
From the introduction on gRPC:
In gRPC a client application can directly call methods on a server application on a different machine as if it was a local object, making it easier for you to create distributed applications and services. As in many RPC systems, gRPC is based around the idea of defining a service, specifying the methods that can be called remotely with their parameters and return types. On the server side, the server implements this interface and runs a gRPC server to handle client calls. On the client side, the client has a stub that provides exactly the same methods as the server.
The above paragraph talks about a client and a server, with the former being the one who is invoking methods to the other. What am I wondering is: can the server-end of the connection invoke methods that have been registered on the client?
No, a server cannot invoke calls on the client. gRPC works with HTTP, and HTTP has not had such semantics in the past.
There has been discussion as to various ways to achieve such a feature, but I'm unaware of any work having started or general agreement on a design. gRPC does support bidirectional streaming, which may get you some of what you need. With bidirectional streaming the client can respond to messages from server, but the client still calls the server and only one type of message can be sent for that call.
The protocol does not implement it, but you may pretend this situation.
Define a server method that returns a stream of a ServerRequest message:
import "google/protobuf/any.proto";
service FullDuplex {
rpc WaitRequests (google.protobuf.Any) returns (stream ServerRequest);
}
message ServerRequest {
float someValue = 1;
float anotherAnother = 1;
}
ServerRequest may be an Oneof, so your may receive different types of server requests.
If you need that your client sends back a response for each request, you may create a stream from your client to the server, but you will need to implement a logic in your server side that triggers a timeout waiting for that response.
service FullDuplex {
rpc WaitRequests (stream ClientResponse) returns (stream ServerRequest);
}
What you can do is start a HTTP server in both processes and use clients at each end to initiate communication. There's a bit of boilerplate involved and you have to design a simple handshaking protocol (one end registers with the other, advertising its listen address) but it's not too much work.
I have a very simple netty app which serves both as server and a client.
Client uses channel.writeAndFlush() to send request to server and then blocks on monitor.wait().
In client's InboundAdapter in channelRead() I find the appropriate monitor and do monitor.notify() to let the requesting client thread to proceed working on the server's reply.
On the server in ChannelHandler's channelRead() I do the following:
To limit the amount of requests being processed I submit a task which does the real work as a new task to existing EventLoop: ctx.executor().submit(new Task()). I that task I do heavy IO operations and after that I writeAndFlush() results back to client.
Here is my pipeline setup:
new ObjectEncoder(),
new ObjectDecoder(LibConstants.Search.MAX_REQUIEST_SIZE, ClassResolvers.cacheDisabled(null))
Here is the bootstrap config:
new ServerBootstrap()
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1000)
.option(ChannelOption.SO_KEEPALIVE, true)
I have 2 problems:
Rather often I get io.netty.handler.codec.DecoderException: java.io.UTFDataFormatException on the client when receiving a reply from server. I cannot find any obvious reason for this. Since my pipeline setup is so simple.
A reply from the server just wouldn't appear on the client. I the logs I see a successful flush on the server but the reply never arrived at the client. This is very hard to deal with since my app is very latency sensitive. Any timeout I would set will kill my user experience.
This all happens over a VPN network so there is a possibility that VPN device misbehaves in some weird way but I hoping that TCP would handle any sort of packet loss/corruption which can happen in the channel.
Any advice or experience you can share will be very appreciated!
I have a web service that is running on IIS (6 or 7, doesn't matter) and I would like to know the port that the caller has sent their request/invocation from.
So if a client makes a call on my web service, how do I find out from the server side what the port number is they made the call from?
Is that something that even gets passed at even the lowest level? Just to be clear I'm not looking for the port for callback purposes. It's for logging only.
You should be able to find it as "REMOTE_PORT" in the server variables of the Server object.
However, this port should pretty much always be random, and is only active for the Request/Response pair the client is making. It should be can't be used for asynchronous call backs. Even your webservice when calling to someother service will use a random port number to initiate the request from. The only static port in the communication is the receiving port at the server end of the TCP connection.
If you service is on WCF, then:
OperationContext context = OperationContext.Current;
MessageProperties messageProperties = context.IncomingMessageProperties;
var endpointProperty = messageProperties[RemoteEndpointMessageProperty.Name]
as RemoteEndpointMessageProperty;
if (endpointProperty != null)
{
string sRemoteAddress = endpointProperty.Address;
int nRemotePort = endpointProperty.Port;
}
TCP sockets do have the concept of sender port number but it doesn't have much use in application level protocols. That said, considering the last paragraph of the OP, I think you're looking for some way to call back the client. The ports I said previously cannot be used for that. Asynchronous requests are identical to synchronous ones running on a separate thread, nothing special about them.
Some Network Address Translation-type devices will hide the actual "sending" port number from you. You would then have access to a useless IP address and a useless port number.