I have an http web server that I'm trying to detect long-running requests and abort them. The following code successfully returns to the client upon timeout, but the async zone still continues to run to completion. How can I actually kill the request handler?
var zone = runZoned(() {
var timer = new Timer(new Duration(seconds: Config.longRequestTimeoutSeconds), () {
if (!completer.isCompleted) { // -- not already completed
log.severe('request timed out');
// TODO: This successfully responds to the client early, but it does nothing to abort the zone/handler that is already running.
// Even though the client will never see the result (and won't have to wait for it), the zone/handler will continue to run to completion as normal.
// TODO: Find a way to kill/abort/cancel the zone
completer.complete(new shelf.Response(HttpStatus.SERVICE_UNAVAILABLE, body: 'The server timed out while processing the request'));
}
});
return innerHandler(request) // -- handle request as normal (this may consist of several async futures within)
.then((shelf.Response response) {
timer.cancel(); // -- prevent the timeout intercept
if (!completer.isCompleted) { // -- not already completed (not timed out)
completer.complete(response);
}
})
.catchError(completer.completeError);
});
Nothing can kill running code except itself. If you want code to be interruptible, you need some way to tell it, and the code itself needs to terminate (likely by throwing an error). In this case, the innerHandler needs to be able to interrupt itself when requested. If it's not your code, that might not be possible.
You can write a zone that stops execution of asynchronous events when a flag is set (by modifying Zone.run etc.), but you must be very careful about that - it might never get to an asynchronous finally block and release resources if you start throwing away asynchronous events. So, that's not recommended as a general solution, only for very careful people willing to do manual resource management.
Related
I have a Quarkus application where I use the event bus.
the code in question looks like this:
#ConsumeEvent(value = "execution-request", blocking = true)
#Transactional
#TransactionConfiguration(timeout = 3600)
public void consume(final Message<ExecutionRequest> msg) {
try {
execute(...);
} catch (final Exception e) {
// some logging
}
}
private void execute(...)
throws InterruptedException {
// it actually runs a long running task, but for
// this example this has the same effect
Thread.sleep(65000);
}
Why do I still get a
WARN [io.ver.cor.imp.BlockedThreadChecker] (vertx-blocked-thread-checker) Thread Thread[vert.x-worker-thread-0,5,main] has been blocked for 63066 ms, time limit is 60000 ms: io.vertx.core.VertxException: Thread blocked
I'm I doing something wrong? Is the blocking parameter at the ConsumeEvent annotation not enough to let that handle in a separate Worker?
Your annotation is working as designed; the method is running in a worker thread. You can tell by both the name of the thread "vert.x-worker-thread-0", and by the 60 second timeout before the warnings were logged. The eventloop thread only has a 3 second timeout, I believe.
The default Vert.x worker thread pool is not designed for "very" long running blocking code, as stated in their docs:
Warning:
Blocking code should block for a reasonable amount of time (i.e no more than a few seconds). Long blocking operations or polling operations (i.e a thread that spin in a loop polling events in a blocking fashion) are precluded. When the blocking operation lasts more than the 10 seconds, a message will be printed on the console by the blocked thread checker. Long blocking operations should use a dedicated thread managed by the application, which can interact with verticles using the event-bus or runOnContext
That message mentions blocking for more than 10 seconds triggers a warning, but I think that's a typo; the default is actually 60.
To avoid the warning, you'll need to create a dedicated WorkerExecutor (via vertx.createSharedWorkerExecutor) configured with a very high maxExcecuteTime. However, it does not appear you can tell the #ConsumeEvent annotation to use it instead of the default worker pool, so you'd need to manually create an event bus consumer, as well, or use a regular #ConsumeEvent annotation, but call workerExectur.executeBlocking inside of it.
I have a server-side streaming gRPC service that may have messages coming in very rapidly. A nice to have client feature would be to know there are more updates already queued by the time this onNext execution is ready to display in the UI, as I would simply display the next one instead.
StreamObserver< Info > streamObserver = new StreamObserver< info >( )
{
#Override
public void onNext( Info info )
{
doStuffForALittleWhile();
if( !someHasNextFunction() )
render();
}
}
Is there some has next function or method of detection I'm unaware of?
There's no API to determine if additional messages have been received, but not yet delivered to the application.
The client-side stub API (e.g., StreamObserver) is implemented using the more advanced ClientCall/ClientCall.Listener API. It does not provide any received-but-not-delivered hint.
Internally, gRPC processes messages lazily. gRPC waits until the application is ready for more messages (typically by returning from StreamObserver.onNext()) to try to decode another message. If it decodes another message then it will immediately begin delivering that message.
One way would be to have a small, buffer with messages from onNext. That would let you should the current message, and then check to see if another has arrived in the mean time.
When the Meteor server connection is lost, how can I verify that Meteor.call() failed? Meteor.call() doesn't return any value. Basically Ctrl+Z in the Meteor shell when your app is running, then do something in the app that triggers a Meteor.call i.e. adding a new blog post:
Meteor.call('createPhrase', phrase, function(error) {
console.log("This NEVER gets called if server is down.");
if (error) {
throwError(error.reason);
}
});
I tried using Session vars, but the reactivity screws it up, i.e. the code below will trigger an error in my template handler (that get's flashed to the browser quickly) and as soon as isMyError is set to true, then when the Meteor.call is successful the error goes away as per isMyError = false, but this looks really sloppy.
Session.set("isMyError", true);
Meteor.call('createPhrase', phrase, function(error) {
console.log("This NEVER gets called if server is down.");
Session.set("isMyError", false);
if (error) {
throwError(error.reason);
}
});
Template.index.isMeteorStatus = function () {
myClientStatus = Meteor.status();
if ( (myClientStatus.connected === false) || (Session.get("isMyError") === true) ) {
return false;
} else {
return true;
}
};
Meteor's calls are generally entered into a queue that are sent to the server in the order that they are called. If there is no connection they stay in the queue until the server is connected once more.
This is the reason nothing is returned because Meteor hopes that it can reconnect then send the call and when it does it does eventually return a result then.
If you want to validate whether the server is connected at the point of the call it's best to check Meteor.status().connected (which is reactive) and only run Meteor.call if it is else throw an error
if(Meteor.status().connected)
Meteor.call(....
else throwError("Error - not connected");
You could also use navigator.onLine to check whether the network is connected.
The reason you would experience a 60 second delay with Meteor.status().connected on the true status of whether meteor is connected or not is there isn't really a way for a browser to check if its connected or not.
Meteor sends a periodic heartbeat, a 'h' on the websocket/long polling wire to check it is connected. Once it realizes it didn't get a heartbeat on the other end it marks the connection disconnected.
However, it also marks it as disconnected if a Meteor.call or some data is sent through and the socket isn't able to send any data. If you use a Meteor.call beforehand to Meteor.status().connected it would realize much sooner that it is disconnected. I'm not sure it would realize it immediately that you can use them one line after the next, but you could use a Meteor.setTimeout after a second or two to fire the call.
Attempt to succeed:
Meteor is designed very well to attempt to succeed. Instead of 'attempting to fail' with an error stating the network is not available its better to try and queue everything up until the connection is back.
The best thing to do would be to avoid telling the user the network is down because usually they would know this. The queued tasks ensure the userflow would be unchanged as soon as the connection is back.
So it would be better to work with the queues that are built into the reconnection process rather than to avoid them.
I have a web service that can be broken down into two main sections:
[WebMethod]
MyServiceCall()
{
//Do stuff the client cares about
//Do stuff I care about
}
What I'd like to do is run that 2nd part on another thread, so that the client isn't waiting on it: once the user's logic has completed, send them their information immediately, but continue processing the stuff I care about (logging, etc).
From a web service, what is the recommended way of running that 2nd piece asynchronously, to get the user back their information as quickly as possible? BackgroundWorker? QueueUserWorkItem?
You may want to look into Tasks which are new to .NET 4.0.
It lets you kick off an asynchronous operation, but also gives you an easy way to see if it's done or not later.
var task = Task.Factory.StartNew(() => DoSomeWork());
It'll kick off DoSomeWork() and continue without waiting so you can continue doing your other processing. When you get to the point where you don't want to process anymore until your asynchronous task has finished, you can call:
task.Wait();
Which will wait there until the task has completed. If you want to get a result back from the task, you can do this:
var task = Task.Factory.StartNew(() =>
{
Thread.Sleep(3000);
return "dummy value";
});
Console.WriteLine(task.Result);
A call to task.Result blocks until the result is available.
Here's a tutorial that covers Tasks in greater detail: http://www.codethinked.com/net-40-and-systemthreadingtasks
The easiest way to fire off a new thread is probably:
new Thread(() =>
{
/// do whatever you want here
}).Start();
Be careful, though - if the service is hit very frequently, you could wind up creating a lot of threads that block each other.
is it possible to stop a web service from executing?
I have a flex web application that searches clients with both full name and client id, when searching by name sometimes the usuer just types the last name and it takes a long time.
Since the app is used when clients are waiting in line, I would like to be able to stop the search and use their full name or id instead, and avoid waiting for the results and then having to search the user manually within the results.
thanks
edit: Sorry, I didn't explain myself correctly, when I meant "web service" I actually meant mx.rpc.soap.mxml.WebService, I want to stop it from waiting for the result event and the fault event. thanks.
There is actually a cancel(..) method explicitly for this purpose, though it is a little burried. Using the cancel method will cause the result and fault handlers not to be called and will also remove the busy cursor etc.
Depending on how you run your searches (ie. separate worker process etc), it is also possible to extend this by added in a cancelSearch() web service method to kill these worker processes and free up server resources etc.
private var _searchToken:AsyncToken;
public function doSearch(query:String):void
{
_searchToken = this.searchService.doSearch(query);
}
protected function doSearch_resultHandler(event:ResultEvent):void
{
trace("doSearch result");
trace("TODO: Do stuff with results");
_searchToken = null;
}
protected function doSearch_faultHandler(event:FaultEvent):void
{
trace("doSearch fault: " + event.fault);
_searchToken = null;
}
public function cancelSearch():void
{
var searchMessageId:String = _searchToken.message.messageId;
// Cancels the last service invocation or an invokation with the
// specified ID. Even though the network operation may still
// continue, no result or fault event is dispatched.
searchService.getOperation("doSearch").cancel(searchMessageId);
_searchToken = null;
trace("The search was cancelled, result/fault handlers not called");
// TODO: If your web service search method is using worker processes
// to do a search and is likely to continue processing for some time,
// you may want to implement a 'cancel()' method on the web service
// to stop any search threads that may be running.
}
Update
You could use disconnect() to remove any pending request responders, but it also disconnects the service's connection. Then call initialize().
/Update
You cannot stop the web service from executing, because that's beyond the Flex app's control, but you can limit the processing of the web service's response. For instance on the app, have a button like Cancel Search which sets a boolean bSearchCanceled to true.
The result handler for the web service call checks bSearchCanceled; if true just return.