WebRequest doomed to failure when starting from parallel thread - c#

Consider following console application:
public static void Request(string url)
{
ThreadPool.QueueUserWorkItem((state) =>
{
try
{
var request = WebRequest.Create(url);
request.Timeout = 5000;
request.GetResponse();
}
catch (Exception e)
{
Console.Out.WriteLine(e);
}
Console.Out.WriteLine(url);
});
}
static void Main(string[] args)
{
Request("http://google.com?q=a");
Request("http://google.com?q=b");
Request("http://google.com?q=c");
Request("http://google.com?q=d");
Thread.Sleep(20000);
Console.In.ReadLine();
}
Output will finish for 2 urls. But for the rest it will throw "The operation has timed out".
I know that there is a limit of parallel connections by default set to two. If I increase it to three then three will finish up.
I.E:
ServicePointManager.DefaultConnectionLimit = 3;
But my question is - why the rest of them doesn't finish up, but throws the operation has timed out instead ?

Because the timeout includes the time the process was waiting in line for a connection to become available.
The timeout to represents "I want to wait at most 5000ms after I call GetResponse() to get my response" not "I want to wait at most an additional 5000ms after GetResponse() has waited for a unlimited amount of time to get its turn in the queue."
Now, you wonder, "but the query is so quick, it should not take more than 5000ms to complete!". The problem comes from the fact you did not close the response you got from GetResponse, from the MSDN:
You must call the Close method to close the stream and release the
connection. Failure to do so may cause your application to run out of
connections.
Calling Dispose() implicitly calls Close(), so if you update your code to dispose of your response then the used connection will become freed and one of the waiting requests will then be able to start up.
public static void Request(string url)
{
ThreadPool.QueueUserWorkItem((state) =>
{
try
{
var request = WebRequest.Create(url);
request.Timeout = 5000;
using(var response = request.GetResponse())
{
Console.Out.WriteLine("Response - " + url);
}
}
catch (Exception e)
{
Console.Out.WriteLine(e);
}
Console.Out.WriteLine("Method End - " + url);
});
}
static void Main(string[] args)
{
Request("http://google.com?q=a");
Request("http://google.com?q=b");
Request("http://google.com?q=c");
Request("http://google.com?q=d");
Thread.Sleep(20000);
Console.In.ReadLine();
}

Related

C # HttpWebRequest , Fire and forget an API call

In my WCF service, I have to make a call to an API, where I wanted to do a Fire and Forget implementation. And If possible just capture the errors if any.(That's fine too , if not an option)
I am planning to do the following implementation, what are the issues it could lead to? By doing the following implementation is going to leave a huge number of open connections. Or what could be the issue? Please help in understanding how in a better way this can be implemented.
void SendRequest(inputs)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "application/xml";
byte[] requestBytes = Encoding.UTF8.GetBytes(inputXML);
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(requestBytes, 0, requestBytes.Length);
}
request.GetResponseAsync();
}
Main()
{
try
SendRequest(inputs);
catch ex
log ex;
}
First, make fully async version of your code
using System.Threading;
public async Task<System.Net.WebResponse> SendRequestAsync(
string inputXML, string url, CancellationToken cancellationToken)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/xml";
byte[] requestBytes = Encoding.UTF8.GetBytes(inputXML);
// GetRequestStreamAsync is a lightweight operation I assume
// so we don't really need any cancellation
using (Stream requestStream = await request.GetRequestStreamAsync())
{
// Idk if we really need cancellation here, but just in case of big request we might need to
await requestStream.WriteAsync(
requestBytes, 0, requestBytes.Length, cancellationToken);
}
// Close any long-running request
using (cancellationToken.Register(() => request.Abort(), useSynchronizationContext: false))
{
var response = await request.GetResponseAsync();
cancellationToken.ThrowIfCancellationRequested();
return response;
}
}
Let's create an async void method, but make it safe. It will basically execute in "fire-and-forget" manner.
public async void DoWork(string inputXML, string url, CancellationToken ct)
{
try
{
using(var response = await SendRequestAsync(inputXML, url, ct))
{
var httpResponse = (HttpWebResponse) response;
// Use 201 Created or whatever you need
if (httpResponse.StatusCode != HttpStatusCode.Created)
{
// TODO: handle wrong status code
}
}
}
catch (Exception e)
{
if (ct.IsCancellationRequested)
{
Console.WriteLine("Cancelled");
}
else
{
// TODO: handle exception
}
}
}
private static CancellationTokenSource _cts = new CancellationTokenSource();
public static void Main (string[] args)
{
DoWork("xml string", "example.com", cts.Token);
Console.WriteLine("Boom!");
if (Console.ReadLine() == "exit")
{
// Cancel the damn job
cts.Cancel();
}
}
It's important to handle all errors from inside a DoWork, because following will not work
// Warning, will NOT catch an exception
public static void Main (string[] args)
{
try
{
DoWork("xml string", "example.com");
}
catch (Exception e)
{
}
}
EDIT: OP requested cancellation so I added cancellation
Please note that it's not best practice not to use fire and forget, especially if this a core layer of the application and you might miss important exceptions. When you use this technique you have to remember that the following happens:
Exception will be fail silently without any chance of catching them. normally you will want to log them or get a notification.
You have no idea when the code completes,
Since You don't need the code to complete and it might may not run to you would have no notification that it failed to complete.
A good case scenario for using this technique could be for updating a cache for an example.
Having said that, you could use the following techniques:
NET 4.5 allows us to use it via Task.Run
Task.Run(() => FireAndForget());
You could also start a thread with parameterless lambda:
(new Thread(() => {
FireAndForget();
}) {
Name = "Running Work Thread (FireAndForget)",
Priority = ThreadPriority.BelowNormal
}).Start();

Give code limited amount of time to execute within

I have a line of code in an app that looks like this:
string botMessage = chatterBotSession.Think(input);
It's querying a chat bot service and stores the response in botMessage. Sometimes however, the chat bot can take too long to think of a response.
Is there a way I can run the code like normal, but if it doesn't complete in one second cancel it and then run some handler that can alert the user that the service took too long?
Like, normally I might do this:
string botMessage = chatterBotSession.Think(input);
Console.WriteLine("The bot responded with: " + botMessage);
but if the bot is slow the second line doesn't get executed (fast enough). How can I limit the bot's "thinking" time to one second, and run the rest of the code (that would normally run) as soon as it completes if it was successful or run a separate bit of code to display an error message if it hasn't completed.
You can wrap the bot's service call in a Task.Run call and wait for it a predefined amount of time. It would look something like this
static void Main(string[] args)
{
var task = Task.Run(() => chatterBotSession.Think(input));
if (task.Wait(1000))
{
Console.WriteLine(task.Result);
}
else
{
Console.WriteLine("Couldn't get an answer in a timely manner");
}
Console.ReadLine();
}
It is very easy to limit the task execution by using CancellationTokenSource with timeout:
var cancellationToken = new CancellationTokenSource();
var task = chatterBotSession.Think(cancellationToken.Token);
cancellationToken.CancelAfter(TimeSpan.FromMilliseconds(1000)); // cancel after 1sec
await task;
In Think method you should add call to CancellationToken.ThrowIfCancellationRequested
Calling Bot:
static void Main(string[] args)
{
TalkingBot bot = new TalkingBot();
try
{
Console.WriteLine("Thinking started...");
Console.WriteLine(bot.Think("Some input...", 2000));
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}", ex.Message);
}
Console.ReadLine();
}
And Bot itself:
class TalkingBot
{
string input = null;
int timeout = 0;
string asyncThnikResult = null;
public string Think(string input, int timeout)
{
DateTime timeLimit = DateTime.Now.AddMilliseconds(timeout);
this.input = input;
this.timeout = timeout;
System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(AsyncThnik));
thread.Start();
//wait for result, in this case
while (string.IsNullOrEmpty(asyncThnikResult))
{
if (timeLimit <= DateTime.Now)
{
throw new Exception("Timeout occured!");
}
System.Threading.Thread.Sleep(10);
}
//return result...
return this.asyncThnikResult;
}
/// <summary>
/// Do your thing async...
/// </summary>
void AsyncThnik()
{
string temp = "This value will never be returned due to timeout limit...";
System.Threading.Thread.Sleep(timeout + 1000); //add second to produce timeout...
this.asyncThnikResult = temp;
}
}

C# async await for pooling

I need to do some WebRequest to a certain endpoint every 2 seconds. I tried to do it with a Timer, the problem is that every call to the callback function is creating a different Thread and I'm havind some concurrence problems. So I decided to change my implementation and I was thinking about using a background worker with a sleep of two seconds inside or using async await but I don't see the advantages of using async await. Any advice? thank you.
This is the code that I will reimplement.
private void InitTimer()
{
TimerCallback callback = TimerCallbackFunction;
m_timer = new Timer(callback, null, 0, m_interval);
}
private void TimerCallbackFunction(Object info)
{
Thread.CurrentThread.Name = "Requester thread ";
m_object = GetMyObject();
}
public MyObject GetMyObject()
{
MyObject myobject = new MyObject();
try
{
MemoryStream responseInMemory = CreateWebRequest(m_host, ENDPOINT);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyObject));
myObject = (MyObject) xmlSerializer.Deserialize(responseInMemory);
}
catch (InvalidOperationException ex)
{
m_logger.WriteError("Error getting MyObject: ", ex);
throw new XmlException();
}
return myObject;
}
private MemoryStream CreateWebRequest(string host, string endpoint)
{
WebRequest request = WebRequest.Create(host + endpoint);
using (var response = request.GetResponse())
{
return (MemoryStream) response.GetResponseStream();
}
}
EDIT: I have read this SO thread Async/await vs BackgroundWorker
async await is also concurrence. If you have concurrence problems and you want your application to have only one thread, you should avoid using async await.
However the best way to do WebRequest is to use async await, which does not block the main UI thread.
Use the bellow method, it will not block anything and it is recommended by Microsoft. https://msdn.microsoft.com/en-us/library/86wf6409(v=vs.110).aspx
private async Task<MemoryStream> CreateWebRequest(string host, string endpoint)
{
WebRequest request = WebRequest.Create(host + endpoint);
using (var response = await request.GetResponseAsync())
{
return (MemoryStream)response.GetResponseStream();
}
}
You don't mention what the concurrency problems are. It may be that the request takes so long that the next one starts before the previous one finishes. It could also be that the callback replaces the value in my_Object while readers are accessing it.
You can easily make a request every X seconds, asynchronously and without blocking, by using Task.Delay, eg:
ConcurrentQueue<MyObject> m_Responses=new ConcurrentQueue<MyObject>();
public async Task MyPollMethod(int interval)
{
while(...)
{
var result=await SomeAsyncCall();
m_Responses.Enqueue(result);
await Task.Delay(interval);
}
}
This will result in a polling call X seconds after the last one finishes.
It also avoids concurrency issues by storing the result in a concurrent queue instead of replacing the old value, perhaps while someone else was reading int.
Consumers of MyObject would call Dequeue to retrieve MyObject instances in the order they were received.
You could use the ConcurrentQueue to fix the current code too:
private void TimerCallbackFunction(Object info)
{
Thread.CurrentThread.Name = "Requester thread ";
var result=GetMyObject();
m_Responses.Enqueue(result);
}
or
private async void TimerCallbackFunction(Object info)
{
Thread.CurrentThread.Name = "Requester thread ";
var result=await GetMyObjectAsync();
m_Responses.Enqueue(result);
}
if you want to change your GetObject method to work asynchronously.
Since your request seems to take a long time, it's a good idea to make it asynchronous and avoid blocking the timer's ThreadPool thread while waiting for a network response.

Multithread answering for HttpListener

I have single thread process which executes some long time. I need several users to have access to execute this process and I choose http protocol to manage invocation.
Naturally, when one process is working everybody else should wait till it's done. If process is available it executes. If not then BUSY answer is sent.
Here is implementation:
using System;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace simplehttp
{
class Program
{
private static System.AsyncCallback task;
private static System.Threading.ManualResetEvent mre = new System.Threading.ManualResetEvent(false);// Notifies one or more waiting threads that an event has occurred.
private static HttpListenerContext workingContext = null;
public static bool isBackgroundWorking()
{
return mre.WaitOne(0);
}
static void Main(string[] args)
{
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
while (true)
{
Console.WriteLine(" waitOne " + isBackgroundWorking());
mre.WaitOne(); // Blocks the current thread until the current WaitHandle receives a signal.
Console.WriteLine(" do job" + " [" + Thread.CurrentThread.Name + ":" + Thread.CurrentThread.ManagedThreadId + " ]\n");
HttpListenerRequest request = workingContext.Request;
HttpListenerResponse response = workingContext.Response;
string responseString = "WORK " + DateTime.Now ;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
System.IO.Stream output = response.OutputStream;
Thread.Sleep(10000);
output.Write(buffer, 0, buffer.Length);
output.Close();
Console.WriteLine(" " + responseString + "\t" + DateTime.Now);
workingContext = null;
mre.Reset(); // Sets the state of the event to nonsignaled, causing threads to block.
}
}).Start();
// Create a listener.
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://localhost:6789/index/");
listener.Start();
Console.WriteLine("Listening..." + " [" + Thread.CurrentThread.Name + ":" + Thread.CurrentThread.ManagedThreadId + " ]\n");
task = new AsyncCallback(ListenerCallback);
IAsyncResult resultM = listener.BeginGetContext(task,listener);
Console.WriteLine("Waiting for request to be processed asyncronously.");
Console.ReadKey();
Console.WriteLine("Request processed asyncronously.");
listener.Close();
}
private static void ListenerCallback(IAsyncResult result)
{
HttpListener listener = (HttpListener) result.AsyncState;
//If not listening return immediately as this method is called one last time after Close()
if (!listener.IsListening)
return;
HttpListenerContext context = listener.EndGetContext(result);
listener.BeginGetContext(task, listener);
if (workingContext == null && !isBackgroundWorking())
{
// Background work
workingContext = context;
mre.Set(); //Sets the state of the event to signaled, allowing one or more waiting threads to proceed.
}
else
{
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
string responseString = "BUSY "+ DateTime.Now + " [" + Thread.CurrentThread.Name + ":" + Thread.CurrentThread.ManagedThreadId;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
Console.WriteLine(responseString + "\t" + DateTime.Now);
}
}
}
}
To test I do 2 http calls. I expect have 2 different answers WORK and BUSY.
However I see that second request waits first to finish and then executes.
waitOne False
Listening... [:10 ]
Waiting for request to be processed asyncronously.
do job [:11 ]
WORK 1/24/2016 10:34:01 AM 1/24/2016 10:34:11 AM
waitOne False
do job [:11 ]
WORK 1/24/2016 10:34:11 AM 1/24/2016 10:34:21 AM
waitOne False
What is wrong in my understanding how it should work?
Update (too many comments are not ecouraged by SO):
My code looks awkward because it is replication of real process. In "my" application working process is main process which has has "courtesy" to run embedded C# code at some particular moments. So, I cannot run new task to process request and it must be asyncronious since working process does its own job and only invokes slave piece of code to notify clients when data is available. It is asyncroinious because code is invoked and should finish as soon as possible or it will block master application.
I'll try to add additional thread with synchronous call and see hot it affects situation.
Debugger is not used in this example to not interfere with real time process and time stamps printed to Console. Debugging is great and necessary but in this case I try to substitute with output to avoid extra actor in synchronization/waiting scenario.
The application itself is not heavy loaded conversation. 1-3 clients seldom ask main application for answer. http protocol is used for convenience not for heavy or often conversations. It appears that some browsers like IE work fine (Windows to Windows conversation?) and some like Chrome (more system agnostic) replicate my application behavior. Look at the time stamps, Chrome, IE,IE,Chrome and last Chrome still went to WORK process. BTW, code is changed per conversation suggestion and now new request is placed immediately after retrieving previous one.
HttpListenerContext context = listener.EndGetContext(result);
listener.BeginGetContext(task, listener);
Also, following suggestions, I had change asyncronious call to syncroniuos and result is still the same
private static void ListenerCallback(IAsyncResult result)
{
HttpListener listener = (HttpListener) result.AsyncState;
//If not listening return immediately as this method is called one last time after Close()
if (!listener.IsListening)
return;
HttpListenerContext context = listener.EndGetContext(result);
while (true)
{
if (workingContext == null && !isBackgroundWorking())
{
// Background work
workingContext = context;
mre.Set(); //Sets the state of the event to signaled, allowing one or more waiting threads to proceed.
}
else
{
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
string responseString = "BUSY " + DateTime.Now + " [" + Thread.CurrentThread.Name + ":" +
Thread.CurrentThread.ManagedThreadId;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
Console.WriteLine(responseString + "\t" + DateTime.Now);
}
context=listener.GetContext();
}
}
The code as posted works exactly like it should:
Can't reproduce. I guess that answers the question because apparently you're driving the test workload incorrectly. I drove it by repeatedly clicking the Fiddler composer send button.
Thanks for posting executable code, though. I should have tried that earlier!
I have not totally read and understood that code. It's structure is awkward. Here's a much cleaner structure that's easy to get right:
while (true) {
var ctx = GetContext();
Task.Run(() => ProcessRequest(ctx));
}
That simply dispatches all incoming work. Then:
object #lock = new object(); //is work being done?
void ProcessRequest(Context ctx) {
if (!Monitor.Enter(#lock))
SendBusy();
else {
ProcessInner(ctx); //actually do some work
Monitor.Exit(#lock);
}
}
That's really all that is necessary.
In particular it is pointless for you to use async IO. I assume you have copied that code or idea from somewhere. Common mistake. Async IO helps you nothing at all here and convoluted the code.

WebRequest.BeginGetResponse does not work asynchronously

I have C# code and have a problem with webRequest.begingetresponse.
When I try to used it for asynchronous call, the working thread is blocked and waits for the callback to be called. But, as I read in documentation, the current thread should continue to run and the callback method should be invoked by a different thread once the response is back from the server.
[UPDATE] Actually getting the response back from the server is where the current thread is blocked, and when I check the thread IDs, the thread which calls the callback is the same thread who sent the request.
Any idea what I might be missing?
Here's a snippet of the code:
public class MyRequestState
{
public WebRequest Request;
public WebResponse Response;
public ManualResetEvent allDone = new ManualResetEvent(false);
public MyRequestState()
{
Request = null;
Response = null;
}
}
public class SendRequest
{
private void ResponseCallback(IAsyncResult result)
{
//do sth ...
state.Response = (HttpWebResponse)request.EndGetResponse(result);
//do sth ...
state.allDone.Set();
}
public void MakeWebRequestAsync(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.Proxy = null;
state state = new MyRequestState();
state.Request = request;
IAsyncResult result = request.BeginGetResponse(new System.AsyncCallback(ResponseCallback), state);
state.allDone.WaitOne();
}
}
WebRequest.BeginGetResponse wait for connection synchronously and then receive data asynchronously. If the connection takes some times, it will freeze the calling thread for a while.
You are waiting on your ManualResetEvent right after starting the request. That's why your thread blocks. The thread isn't being signaled to continue until your completed callback is called.

Categories

Resources