I need to send multipart post request from AsyncTask using loopj, so I'm forced to use SyncHttpClient.
Reading the source code comments, I'm learning that a Request Handle returned from the post method of synchronous request cannot be used to cancel the request because it is already complete by the time this returns (which makes sense). Looks like a catch 22 though.
Is there another way to cancel a currently running Synchronous request?
Is it possible to use SyncHttpClient.cancelAllRequests(true); from the UI thread?
Well, SyncHttpClient.cancelAllRequests(true) from the UI thread does not work. Is it a bug?
Just make sure that you can use AsyncHttpRequest if you want to be able to cancel the running request. It doesn't matter if you are running your asynchronous http request from another thread or even an AsyncTask, you just have to make sure that the AsyncHttpRequest is called on the main thread. You can do this easily by forcing it into the main thread using
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = new Runnable() {
public void run() {
// run your AsyncHttpRequest in here.
// Since it is called from the main thread it will run asynchronously
// and therefore it can be cancelled easily by calling client.cancelAllRequests(true)
}
};
mainHandler.post(myRunnable);
Related
I want to be able to call an HTTP endpoint (that I own) from an Azure Function at the end of the Azure Function request.
I do not need to know the result of the request
If there is a problem in the HTTP endpoint that is called I will log it there
I do not want to hold up the return to the client calling the initial Azure Function
Offloading the call of the secondary WebApi onto a background job queue is considered overkill for this requirement
Do I simply call HttpClient.PutAsync without an await?
I realise that the dependencies I have used up until the point that the call is made may well not be available when the call returns. Is there a safe way to check if they are?
My answer may cause some controversy but, you can always start a background task and execute it that way.
For anyone reading this answer, this is far from recommended. The OP has been very clear that they don't care about exceptions or understanding what sort of result the request is returning ...
Task.Run(async () =>
{
using (var httpClient = new HttpClient())
{
await httpClient.PutAsync(...);
}
});
If you want to ensure that the call has fired, it may be worth waiting for a second or two after the call is made to ensure it's actually on it's way.
await Task.Delay(1000);
If you're worried about dependencies in the call, be sure to construct your payload (i.e. serialise it, etc.) external to the Task.Run, basically, minimise any work the background task does.
This questions is related to Return immediately in spring web flux but I don't think it's the same (at least the answer there is not satisfactory for me).
I have a function returning a Mono that when invoked starts a long-running job. This function is invoked when a call is made to a Spring Webflux HTTP API. Here's an example:
#PutMapping("/{jobId}")
fun startNewJob(#PathVariable("jobId") jobId: String,
request: ServerHttpRequest): Mono<ResponseEntity<Unit>> {
val longRunningJob : Mono<Job> = startNewJob(jobId)
longRunningJob.map { job ->
val jobUri = generateJobUri(request, job.id)
ResponseEntity.created(jobURI).build<Unit>()
}
}
The problem with the code above is that "201 Created" is created after the long running job is completed. I want to kick-off the longRunningJob in the background and return "201 Created" immediately.
I could perhaps do something like this:
#PutMapping("/{jobId}")
fun startNewJob(#PathVariable("jobId") jobId: String,
request: ServerHttpRequest): Mono<ResponseEntity<Unit>> {
startNewJob(jobId)
.subscribeOn(Schedulers.newSingle("thread"))
.subscribe()
val jobUri = generateJobUri(request, job.id)
val response = ResponseEntity.created(jobURI).build<Unit>()
Mono.just(response)
}
But it doesn't seem very idiomatic to me to have to call subscribe() manually (e.g. intellij is complaining that I call subscribe() in non-blocking scope). Isn't there a better way to compose the two "streams" without using an explicit subscribe? If so how do I modify the startNewJob function above to achieve this?
AFAIK, using one of the subscribe methods is the only way to really start a job in the background with its own lifecycle (not tied to the returned publisher).
If you were to use one of the operators to combine the job publisher and the response publisher (e.g. zip or merge), then the lifecycle of the job publisher would be tied to the response publisher, which is not what you want for a background job.
One thing you might want to consider is kicking off the background job within the response publisher stream, rather than directly in the method body. e.g. via doOnSubscibe or from an operator upstream of the response.
This would tie the start of the background job to the onSubscribe events of the response publisher, but still allow it to complete in the background.
Also note, that if you want to be able to cancel the background job (e.g. maybe during application shutdown), you'll need to save the Disposable returned from subscribe so you can later call dispose on it. This might be better done from some type of BackgroundJobManager that could keep track of all the jobs running.
private static final Scheduler backgroundTaskScheduler = Schedulers.newParallel("backgroundTaskScheduler", 2);
backgroundTaskScheduler.schedule(() -> doBackgroundJob());
I have a Web API project whose controller in turn makes web requests to a third party REST interface. My controller CRUD functions i have marked as async however the implementation is such that i use HttpWebRequest blocking functions GetRequestStream and GetResponse.
Is this suitable or should i use the Begin/End methods of HttpWebRequest too. This seems like overkill as it would be asyncing an already async operation, or would it allow more concurrent outgoing web requests?
Looking for the best solution for throughput both incoming and outgoing.
the controller is marked async but the implementation uses synchronous HttpWebRequest calls, in that my controller is awaiting Task.Run( sync web request )
Think about what is happening in the request. The request comes in and ASP.NET takes a thread pool thread to handle the request. The controller action queues the work to the thread pool (taking up another thread), and then awaits that work, freeing up the original request thread. You haven't gained anything by using await because there's still a thread pool thread blocking on the web request.
For this reason, you should almost never use Task.Run (or any other method that queues work to the thread pool) on ASP.NET.
Is this suitable or should i use the Begin/End methods of HttpWebRequest too. This seems like overkill as it would be asyncing an already async operation
It's not really asynchronous right now; there's still a thread being blocked. I call this "queue blocking work to a thread pool thread and then await it" technique fake asynchrony.
The appropriate fix is to use HttpClient, which was designed for asynchronous use; or, you could use TaskFactory<T>.FromAsync to wrap the Begin/End methods into an awaitable task.
The thing i dont understand though is if i use await HttpClient.SendAsync then somewhere something must be blocking waiting for a response
No, there doesn't have to be something blocking somewhere. As I describe on my blog, in a truly asynchronous scenario (i.e., not fake-asynchrony), there is no thread.
I would recommend you to retain the async methods, and use HttpClient instead of HttpWebRequest, because it supports asynchronous calls as well.
Let's have a look at a pseudo example of a CarsController calling a third party service.
public class CarsController : ApiController
{
[Route("cars/{id}")]
public async Task<IHttpActionResult> Get(int id)
{
//Get a car by its id
HttpClient client = new HttpClient();
//Read the content directly
string result = await client.GetStringAsync("http://www.google.com");
//process the result returns from the thrid party REST service
return Ok(result);
}
}
As you can see, HttpClient supports reading String/ Stream/ ByteArray asynchronously via GetXXXAsync() methods.
If you want to access to the underlying response content, that can be achieved by using the following code:
[Route("responsecars/{id}")]
public async Task<IHttpActionResult> GetResponseStream(int id)
{
HttpClient client = new HttpClient();
HttpResponseMessage responseMessage =await client.GetAsync("http://www.google.com", HttpCompletionOption.ResponseContentRead);
HttpContent content = responseMessage.Content;
//using one of the ReadAsync methods
string text =await content.ReadAsStringAsync();
return Ok(text);
}
Hope this help.
Asynchrony on the server is separate and independent from asynchrony on the client.
You can call a synchronous Web API method asynchronously from the client with WebRequest.GetResponseAsync, or you can call an asynchronous Web API method synchronously from the client with WebRequest.GetResponse, or you can have asynchrony on both sides, which is probably the best approach. You don't need to use Begin/End APM-style WebRequest APIs, unless you target .NET 4.0 on the client. Use Task-based async APIs instead.
In either case, a complete HTTP request will be sent to the client when your Web API controller method has fully finished, regardless of whether it is implemented as synchronous or asynchronous (Task-based).
I am new to angular and want to use it to send data to my app's backend. In several occasions, I have to make several http post calls that should either all succeed or all fail. This is the scenario that's causing me a headache: given two http post calls, what if one call succeeds, but the other fails? This will lead to inconsistencies in the database. I want to know if there's a way to cancel the succeeding calls if at least one call has failed. Thanks!
Without knowing more about your specific situation I would urge you to use the promise error handling if you are not already doing so. There's only one situation that I know you can cancel a promise that has been sent is by using the timeout option in the $http(look at this SO post), but you can definitely prevent future requests. What happens when you make a $http call is that it returns a promise object(look at $q here). What this does is it returns two methods that you can chain on your $http request called success and failure so it looks like $http.success({...stuff...}).error({...more stuff..}). So if you do have error handling in each of these scenarios and you get a .error, dont make the next call.
You can cancel the next requests in the chain, but the previous ones have already been sent. You need to provide the necessary backend functionality to reverse them.
If every step is dependent on the other and causes changes in your database, it might be better to do the whole process in the backend, triggered by a single "POST" request. I think it is easier to model this process synchronously, and that is easier to do in the server than in the client.
However, if you must do the post requests in the client side, you could define each request step as a separate function, and chain them via then(successCallback, errorCallback) (Nice video example here: https://egghead.io/lessons/angularjs-chained-promises).
In your case, at each step you can check if the previous one failed an take action to reverse it by using the error callback of then:
var firstStep = function(initialData){
return $http.post('/some/url', data).then(function(dataFromServer){
// Do something with the data
return {
dataNeededByNextStep: processedData,
dataNeededToReverseThisStep: moreData
}
});
};
var secondStep = function(dataFromPreviousStep){
return $http.post('/some/other/url', data).then(function(dataFromServer){
// Do something with the data
return {
dataNeededByNextStep: processedData,
dataNeededToReverseThisStep: moreData
}
}, function(){
// On error
reversePreviousStep(dataFromPreviousStep.dataNeededToReverseThisStep);
});
};
var thirdFunction = function(){ ... };
...
firstFunction(initialData).then(secondFunction)
.then(thirdFunction)
...
If any of the steps in the chain fails, it's promise would fail, and next steps will not be executed.
i am building an application for clients to get questions from server and answer it, if the server doesn't have questions i want to go to new screen and print message that try again in few minutes, getting questions is in AsyncTask , if the server doesn't have questions , it will sends in the header of the responds, a header isFindAQuestion with the value false, here is the code on client to ensure if false , i print on LogCat and i see the message = false, but my problems that even if i start new activity with the intent, this activity keep working and show me exception and it is null pointer exception because on the onPostExceute will take a parmeter null and try to process it, i put finish() in the end of false statement but doesn't finish the activity
if (response.getFirstHeader("isFindAQuestion").getValue()
.toString().equals("false")) {
Log.d("message", "false");
Bundle basket = new Bundle();
basket.putString("Message", "sorry no enought questions");
Intent goToAnswerQuestion = new Intent(AnswerQuestion.this,
FinishTime.class);
goToAnswerQuestion.putExtras(basket);
startActivity(goToAnswerQuestion);
finish();
}
Editis it because AsyncTask is working on thread so if the activity is finished, that thread will keep working? and if so how can i stop that thread?
doInBackground is not executed in the UI thread, but in a separeted thread:
invoked on the background thread immediately after onPreExecute()
finishes executing. This step is used to perform background
computation that can take a long time.
If you want to stop your background operation and perform some activities on the UI thread the better thing is to call cancel() and then perform all the stuff you want in the onCancelled callback wich is executed on the UI thread.
From the AsyncTask documentation:
A task can be cancelled at any time by invoking cancel(boolean).
Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns.
To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)
protected void onCancelled (Result result)
Runs on the UI thread after cancel(boolean) is invoked and doInBackground(Object[]) has finished.
The default implementation simply invokes onCancelled() and ignores the result. If you write your own implementation, do not call super.onCancelled(result).