Is it safe to do nested asynchronous calls (websocket calls) with Vaadin like:
var ui1 = UI.getCurrent();
listenableFuture1.addCallback(page1 -> {
ui1.access(() -> {
//update ui here, then:
var ui2 = UI.getCurrent();
listenableFuture1.addCallback(page2 -> {
ui2.access(() -> {
//update ui here, than:
// one more WS call, and so on
}
}
}
}
Also, inside of ui.access block should I use ui reference locked before, or it is safe to use UI.getCurrent() also?
It's safe to arbitrarily nest access calls. What happens behind the scenes is that the task is first added to a queue of pending access tasks. That queue is then purged at a suitable occasion. If the session is currently locked when the task is added, then it is run when the current lock is about to be released. If it's not currently locked, then the thread running access acquires the lock and runs the task right away.
It shouldn't matter whether you reuse and existing reference to UI or use UI.getCurrent() again since both will reference the same instance.
Related
We have a button in the UI, which, when pressed, will make some remote network call in its own coroutine. However, if the user spams the button for whatever reason, it is possible that the remote data might somehow get corrupted. We would like to prevent this by discarding all requests until the current one is completed.
There are many ways to do this. I have create a simple extension function on CoroutineScope to only launch if the CoroutineScope is not active. This is what I have created:
Extension Function
fun CoroutineScope.safeLaunch(dispatcher: CoroutineDispatcher, block: () -> Unit): Job {
return if (!isActive) {
launch(dispatcher) {
block()
}
} else {
launch {}
}
}
Example Use
fun loadNotifications() {
viewModelScope.safeLaunch(IO) {
getNotifications.invoke() // Suspend function invoke should only be from a coroutine or another suspend function
}
}
The problem is, the above won't compile as I get an error saying
Suspend function invoke should only be from a coroutine or another
suspend function
Does anyone know what I'm doing wrong or how to make it work?
There are multiple problems with this code:
Fixing the error you mentioned is very easy and requires to only specify block as suspendable: block: suspend () -> Unit.
isActive doesn't mean the job/scope is actively running something, but that it hasn't finished. isActive in your example always returns true, even before launching any coroutine on it.
If your server can't handle concurrent actions, then you should really fix this on server side. Limiting the client isn't a proper fix as it can be still exploited by users. Also, you need to remember that multiple clients can perform the same action at the same time.
As you mentioned, there are several ways how this situation can be handled on the client side:
In the case of UI and the button, it is probably the best for the user experience to disable the button or overlay the screen/button with a loading indicator. It gives the user the feedback that the operation is running in the background and at the same time it fixes the problem with multiple calls to the server.
In general case, if we just need to limit concurrency and reject any additional tasks while the last one is still running, probably the easiest is to use Mutex:
private val scope = CoroutineScope(EmptyCoroutineContext)
private val mutex = Mutex()
fun safeLaunch(block: suspend () -> Unit) {
if (!mutex.tryLock()) {
return
}
scope.launch {
try {
block()
} finally {
mutex.unlock()
}
}
}
Note we need a separate mutex per scope or per the type of the task. I don't think it is possible to create such utility as a generic extension function, working with any coroutine scope. Actually, we can implement it in a very similar way to your original code, but by looking at the current job's children. Still, I consider such solution hacking and I discourage it.
I often have to execute code on a separate thread that is long running, blocking, instable and\or has a potential to hang forever. Since the existence of TPL the internet is full of examples that nicely cancel a task with the cancellation token but I never found an example that kills a task that hangs. Code that hangs forever is likely to be expected as soon as you communicate with hardware or call some third party code. A task that hangs cannot check the cancellation token and is doomed to stay alive forever. In critical applications I equip those tasks with alive signals that are sent on regular time intervals. As soon as a hanging task is detected, it is killed and a new instance is started.
The code below shows an example task that calls a long running placeholder method SomeThirdPartyLongOperation() which has the potential to hang forever. The StopTask() first checks if the task is still running an tries to cancel it with the cancellation token. If that doesn’t work, the task hangs and the underlying thread is interrupted\aborted old school style.
private Task _task;
private Thread _thread;
private CancellationTokenSource _cancellationTokenSource;
public void StartTask()
{
_cancellationTokenSource = new CancellationTokenSource();
_task = Task.Factory.StartNew(() => DoWork(_cancellationTokenSource.Token), _cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
public void StopTask()
{
if (_task.Status == TaskStatus.RanToCompletion)
return;
_cancellationTokenSource.Cancel();
try
{
_task.Wait(2000); // Wait for task to end and prevent hanging by timeout.
}
catch (AggregateException aggEx)
{
List<Exception> exceptions = aggEx.InnerExceptions.Where(e => !(e is TaskCanceledException)).ToList(); // Ignore TaskCanceledException
foreach (Exception ex in exceptions)
{
// Process exception thrown by task
}
}
if (!_task.IsCompleted) // Task hangs and didn't respond to cancellation token => old school thread abort
{
_thread.Interrupt();
if (!_thread.Join(2000))
{
_thread.Abort();
}
}
_cancellationTokenSource.Dispose();
if (_task.IsCompleted)
{
_task.Dispose();
}
}
private void DoWork(CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(Thread.CurrentThread.Name)) // Set thread name for debugging
Thread.CurrentThread.Name = "DemoThread";
_thread = Thread.CurrentThread; // Save for interrupting/aborting if thread hangs
for (int i = 0; i < 10; i++)
{
cancellationToken.ThrowIfCancellationRequested();
SomeThirdPartyLongOperation(i);
}
}
Although I’ve been using this construct for some years now, I want to know if there are some potential mistakes in it. I’ve never seen an example of a task that saves the underlying thread or gives it a name to simplify debugging, so I’m a bit unsure if this is the right way to go. Comment on any detail is welcome!
Code that hangs forever is likely to be expected as soon as you communicate with hardware or call some third party code.
Communication: absolutely not. There's always a way to timeout with communication APIs, so even with misbehaving hardware, there's no need to force-kill an I/O operation.
Third-party code: only if you're paranoid (or have high demands such as 24x7 automation).
Here's the bottom line:
There's no way to force-kill a task.
You can force-kill a thread, but this can easily cause serious problems with application state, possibility if introducing deadlocks in other parts of the code, and resource leaks.
You can force-kill an appdomain, which solves a large portion of app state / deadlock issues with killing threads. However, it doesn't solve them all, and there's still the problem of resource leaks.
You can force-kill a process. This is the only truly clean and reliable solution.
So, if you choose to trust the third-party code, I recommend that you just call it like any other API. If you require 100% reliability regardless of third-party libraries, you'll need to wrap the third-party dll into a separate process and use cross-process communication to call it.
Your current code force-kills a thread pool thread, which is certainly not recommended; those threads belong to the thread pool, not to you, and this is still true even if you specify LongRunning. If you go the kill-thread route (which is not fully reliable), then I recommend using an explicit thread.
The question is why is this task even hanging at all? I think there's no universal solution to this problem but you should focus on the task to be always responsible and not on forcing to interrupt it.
In this code, it looks like you're looking for a simple thread rather than a task - you shouldn't link tasks to threads - it's very likely that the task will switch to another thread after some async operations and you will end up on killing an innoccent thread that is not connected to your task anymore. If you really need to kill the whole thread then make a dedicated one just for this job.
You shouldn't also name or do anything with any thread that is used for tasks' default pool. Consider this code:
static void Main(string[] args)
{
Task.Run(sth);
Console.Read();
}
static async Task sth()
{
Thread.CurrentThread.Name = "My name";
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(Thread.CurrentThread.Name ?? "No name");
}
the output is:
3
4
No name
Previously I had used SQLITE-NET library for my all sqlite database tasks and it works well.
But my app has huge number of data to insert and it took a lot of time. So I decided to use SQLITE-WinRT wrapper only where bulk insert is needed as SQLITE-WinRT wrapper seems to provide feature like preparing statements then binding data and then execute them which gives faster processing and increases performance.
In my app, there are lots of CRUD operations that uses SQLITE-NET methods and I left as it is since it is hard to completely switch from SQLITE-NET library to SQLITE-WinRT wrapper.
My app has background task that runs and processes some web-service calls and lot of CRUD operations using only SQLITE-NET library.
Whenever I tried to bulk insert using SQLITE-WinRT wrapper using prepared statements, in case background task is running, it always throws Busy exception in SQLITE-NET library. I know its reason, background service does lot of CRUD operations using SLITE-NET library. So while bulk inserting using SQLITE-WinRT wrapper it throws Busy exception as the sqlite database is already doing lot of tasks in background using SQLITE-NET.
So, my question is how to handle this situation. Please suggest me some ideas to handle such cases. I thought of two ideas:
Stopping background service while bulk inserting (In background,
there is series of long tasks like calling web-service and doing work
with SQLite db, stopping background service at once might not be
good idea )
Closing all SQLITE-NET connection (didn't work as expected though)
Any help would be appreciated. Thanks in advance.
While bulk inserting, I started like this:
string dbPath = "collection.sqlite";
var file = await ApplicationData.Current.LocalFolder.GetFileAsync(dbPath);
var db = new SQLiteWinRT.Database(file);
await db.OpenAsync(SqliteOpenMode.OpenReadWrite);
using (var statement = await db.PrepareStatementAsync("INSERT INTO Forms(ServerFormId,FormFileName,FormStatusId,PriorityId) VALUES(?,?,?,?)"))
{
await db.ExecuteStatementAsync("BEGIN TRANSACTION");
statement.Reset();
statement.BindTextParameterAt(1, "0");
statement.BindTextParameterAt(2, formName);
statement.BindTextParameterAt(3, formStatusId);
statement.BindTextParameterAt(4, priorityId);
await statement.StepAsync().AsTask().ConfigureAwait(false);
}
await db.ExecuteStatementAsync("COMMIT TRANSACTION");
SQLite-WinRT: https://blogs.msdn.microsoft.com/andy_wigley/2013/11/21/how-to-massively-improve-sqlite-performance-using-sqlwinrt/
SQLite-net: http://www.codeproject.com/Articles/826602/Using-SQLite-as-local-database-with-Universal-Apps
I'm afraid that the only option is using lock or semaphore before accessing the database.
The lock mechanism guarantees that only one thread does inner code block. Other threads synchronously waits.
readonly object sync = new object();
void MyMethod() {
lock (sync) {
...
}
}
Semaphore is similar, but the inner code block can be executed maximally by n threads.
Please see more info about SemaphoreSlim on MSDN.
I'm trying to enhance an existing Firefox extension which relies on nsIContentPolicy to detect and abort certain network loads (in order to block the resulting UI action, i.e. tab navigation). Then handle loading that resource internally. Under rare circumstances, only after handling the load, it turns out we shouldn't have interrupted the load at all, so we flag it to be ignored and re-start it.
Under e10s/multi-process, that means the parent (where the content policy is running) must send a message to the child (handling the UI for the content) to restart the load. Today, that's done by:
function findMessageManager(aContext) {
// With e10s off, context is a <browser> with a direct reference to
// the docshell loaded therein.
var docShell = aContext && aContext.docShell;
if (!docShell) {
// But with e10s on, context is a content window and we have to work hard
// to find the docshell, from which we can find the message manager.
docShell = aContext
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem).rootTreeItem;
}
try {
return docShell
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
} catch (e) {
return null;
}
};
Which is crazy complex, because e10s is crazy complex. But it works; it generates some object in the parent, upon which I can call .sendAsyncMessage(), and then the addMessageListener() handler in my frame/child script receives it, and does what it needs to do.
I'd like to switch from nsIContentPolicy to http-on-modify-request as it presents more information for making a better determination (block and handle this load?) earlier. Inside that observer I can do:
var browser = httpChannel
.notificationCallbacks.getInterface(Ci.nsILoadContext)
.topFrameElement;
Which gives me an object which has a .messageManager which is some kind of message manager, and which has a .sendAsyncMessage() method. But when I use that .sendAsyncMessage(), the message disappears, never to be observed by the child.
Context: https://github.com/greasemonkey/greasemonkey/issues/2280
This should work in principle, although the docshell tree traversal may do different things in e10s and non-e10s, so you have to be careful there. In e10s rootTreeItem -> nsIContentFrameMessageManager should give you the MM equivalent to a frame script and topFrameElement.frameLoader.messageManager should give you the <browser>'s MM, which pretty much is the parent side counterpart to it.
Potential sources of confusion:
e10s on vs. off
process MM vs. frame MM hierarchy
listening in the wrong frame for the message (registering in all frames might help for debugging purposes)
This is the function I use to find the content message manager:
function contentMMFromContentWindow_Method2(aContentWindow) {
if (!gCFMM) {
gCFMM = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
}
return gCFMM;
}
So maybe get the content window that triggered that request, and then use this function.
I have a simple viewPart offering some text fields to enter parameters for a selenium test. After filling out these fields the user may start the test which approx. needs 30-45 minutes to run. I want my GUI to be alive during this test giving users the chance to do other things. I need a progress monitor.
I tried to put the selenium test in a job containing Display.getDefault().asyncExec to run it. But my GUI freezes after some seconds giving the busyindicator. The selenium does not update any other view but the progress monitor.
Is there another way to ensure that the job wont block my GUI?
Best,
Mirco
Everything executed in (a)syncExec is using the display thread and therefore blocking your UI until it returns. I suggest you use Eclipse Jobs. This will use the progress indicator that the workbench already offers out of the box.
I would suggest to split your code into code that updates the UI and the code that executes other business. Execute all of it in a separate thread, and when you need to retrieve or set some action to the UI then use the "Display.getDefault().asyncExec".
Thread thread = new Thread("Testing") {
// some shared members
public void run() {
someBusiness();
// or use syncExec if you need your thread
// to wait for the action to finish
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
// UI stuff here
// data retrieval
// values setting
// actions trigging
// but no business
}
});
someBusiness();
};
thread.start();