Async Change Streams in MongoDB - c#

I want to listen to a change stream for a collection, without blocking the thread.
In the code below the ForEachAsync will block forever, processing changes as they occur.
using (var cursor = await collection.WatchAsync())
{
await cursor.ForEachAsync(change =>
{
// process change event
});
}
I have tried removing "await" and storing the task in a variable instead, but no changes will be processed before i actually either await or .Wait() the task later.
I would expect that even though I don't await the task, the events would still be processed.
What can I do, so my entire program doesn't block to listen for changes?
I am considering wrapping the functionality in a new thread, but is that really necessary?

I don't have enough reputation to comment (yet) so my feedback in the form of an answer:
You should be working with events (listeners, handlers) instead of await/async in this situation.
It's difficult to elaborate on this without having more information on what you're trying to accomplish.

So, I figured out that the following works...
static void Main(string[] args)
{
Task watchTask = WatchCollection();
// Do other stuff here, while watching...
}
private static async Task WatchCollection()
{
using (var cursor = collection.Watch())
{
await cursor.ForEachAsync(change =>
{
// process change event
});
}
}
While I was attempting to do it like this, which doesn't work:
static void Main(string[] args)
{
using (var cursor = collection.Watch())
{
Task watchTask cursor.ForEachAsync(change =>
{
// process change event
});
}
// Do other stuff here, while watching
}
So, the actual ForEachAsync task is awaited, while the outer Task which wraps the entire functionality is not awaited... I am either too tired or not familiar enough with Tasks to give a good explanation of why one works and the other doesn't.

Related

Why sequential call of AsyncLock within same (UI) thread doesn't work same way as for different threads (like via Task.Run)?

Partially, this question has a bit of similarity with this one, but as another one is not properly asked (and not fully asked) I am trying to ask it in general, so this question can not be considered as a duplication.
The question is about understanding of how AsyncLock actually works. (In this context I am referring to Neosmart.AsyncLock library, however, I consider it uses common approach in AsyncLock implementation).
So. For instance, we have a main thread (let it be a UI-thread):
static void Main(string[] args)
{
Console.WriteLine("Press Esc for exit");
var lck = new AsyncLock();
var doJob = new Action(async () =>
{
using (await lck.LockAsync())
{
// long lasting job
Console.WriteLine("+++ Job starts");
await Task.Delay(TimeSpan.FromSeconds(10));
Console.WriteLine("--- Job finished");
}
});
while (Console.ReadKey().Key != ConsoleKey.Escape)
{
doJob();
}
}
so, sequental pressing of Enter starts doJobevery time without waiting until previous job finished.
However, when we change it to:
Task.Run(() =>
{
doJob();
});
... everything works like a charm, and no new jobs is run until previous finished.
That's clear that async logic is far different than classic lock(_myLock) and can't be comparable directly, however, still, why the first approach doesn't work that way when the second call of LockAsync would "lock" (again, in async context) the "long lasting job" to start until previous finished.
There is actually a practical request of why I need that code to work this way, (and real question is how I can achieve that with await LockAsync?):
For example, in my app (for instance, my mobile app), on very launch there is some data I am starting pre-loading (this is a common service which needs that data to keep in cache for further use), then, when the UI is started, a particular page requests the same data for the UI to appear and asks the same service to load the same data. So, without any custom logic that service would start two long lasting jobs to retrieve the same pack of data. Instead, I want my UI to receive the data from the cache right the data pre-loading finished.
Like that (an abstract possible scenario):
class MyApp
{
string[] _cache = null;
AsyncLock _lock = new AsyncLock();
async Task<IEnumerable<string>> LoadData()
{
using (await _lock.LockAsync())
{
if (_cache == null)
{
await Task.Delay(TimeSpan.FromSeconds(10));
_cache = new[] {"one", "two", "three"};
}
return _cache;
}
}
void OnAppLaunch()
{
LoadData();
}
async void OnMyCustomEvent()
{
var data = await LoadData();
// to do something else with the data
}
}
the problem would be solved if I would change it to Task.Run(async () => { var data = await LoadData(); }) but it doesn't look like quite clean and nice approach.
As Matthew points out in the comments, AsyncLock is reentrant, meaning that if the same thread attempts to take the lock a second time, it recognizes that and allows it to continue. The author of AsyncLock wrote a lengthy article about how reentrance was really the reason he wrote it: AsyncLock: an async/await-friendly locking library for C# and .NET
It's not a bug; it's a feature.™
After the "Update 5/25/2017" heading, there are code examples demonstrating exactly what you are experiencing here and showing how it is a feature.
Reasons to want reentrance are:
If you are just concerned with multiple threads touching the same variable (preventing race conditions), then there is simply no reason to block a thread that already has the lock.
It makes recursive functions that use locks easier to write because you don't need to test if you already have the lock. A lack of reentrance support + sloppy recursive coding = deadlock.
If you really want it to not be reentrant, you can use what he says was not appropriate for reentrance: SemaphoreSlim:
var lck = new SemaphoreSlim(1);
var doJob = new Action(async () => {
await lck.WaitAsync();
try {
// long lasting job
Console.WriteLine("+++ Job starts");
await Task.Delay(TimeSpan.FromSeconds(2));
Console.WriteLine("--- Job finished");
} finally {
lck.Release();
}
});

Call C# Task Repeatedly on conclusion

I have a C# app that must run blocks of code in parallel. Here is the basic structure of two of those blocks of code. In reality, there will be many more.
private async Task MyFirstTask()
{
// do stuff
await FirstTaskImplementation();
// cleanup
}
private async Task MySecondTask()
{
// do stuff
await SecondTaskImplementation();
// cleanup
}
Some of these blocks of code will run on a timer. Some will run repeatedly. In an attempt to accomplish, I have the following:
Task.Run(() => MyFirstTask());
Task.Run(() => MySecondTask());
When MyFirstTask has completed, I want to run it again. In fact, I want to run it over-and-over again until the program stops. Yet, I want MySecondTask to run in parallel of MyFirstTask. My question is, how do I execute MyFirstTask repeatedly, while still being parallel to MySecondTask?
I reviewed several of the related SO questions. I also do not see a Complete kind of event handler. So, I'm kind of lost in terms of how to implement this. I appreciate your help!
The beauty of async/await is that you can write asynchronous code in much the same way you'd write synchronous code. How would you repeat a synchronous operation? You could use a loop. You could do the same here, e.g.:
private async Task MyFirstTask(CancellationToken token) {
while (!token.IsCancellationRequested) {
// do stuff
await FirstTaskImplementation();
// cleanup
}
}
You can embed the loop in your current method or lift it into a wrapper method, but it should work either way.
You can continue scheduling your tasks the same way you're doing it now, though you really should await your async methods:
CancellationTokenSource cts = new CancellationTokenSource();
Task.Run(async () => await MyFirstTask(cts.Token));
Task.Run(async () => await MySecondTask());
// Request cancellation via `cts` when you want the looping to end.
And although you didn't ask about it, if you wanted to insert a delay between each iteration, you could simply place an await Task.Delay(...) statement at the end of the loop body.
You don't necessarily need to use Task.Run for the first task. You can use a Timer for the first task, with AutoReset set to true. That way it'll run forever and you don't have to worry about it anymore.
private static System.Timers.Timer aTimer;
public static void Main()
{
SetTimer(); //MyFirstTask starts running over and over in another thread
Task.Run(() => MySecondTask());
}
private static void SetTimer()
{
// Create a timer with a 1ms interval (has to be > 0)
aTimer = new System.Timers.Timer(1);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += MyFirstTask;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private static async void MyFirstTask(Object source, ElapsedEventArgs e)
{
// do stuff
await FirstTaskImplementation();
// cleanup
}
private async Task MySecondTask()
{
// do stuff
await SecondTaskImplementation();
// cleanup
}
Another approach would be something like this:
var first=MyFirstTask().ToObservable();
var second=MySecondTask().ToObservable();
first.Repeat().Merge(second).Subscribe(x=>Console.WriteLine("Task completing."));
That's illustrative, not tested code. If you expect MySecondTask to complete, then perhaps this:
first.Repeat().TakeUntil(second).Subscribe(x=>Console.WriteLine("Task completing."));
If you want to add timeouts to second you could do this:
first.Repeat().TakeUntil(second.Timeout(TimeSpan.FromMilliseconds(100))).Subscribe(...)
If you want to show something on each task completion, declare the observables as:
var first=MyFirstTask().ToObservable().Do(Console.WriteLine("First completing"));
The above requires System.Reactive.Linq namespaces. I find these Rx based solutions to concurrency generally more elegant than the TPL, but that's just subjective.
Finally, if you do not want to start the tasks until the subscription is called, or something is ready to start watching, you can use Observable.FromAsync , as per info here

What causes a Task to complete?

I'm trying to find out how to use WhenAll to let two methods run at once, and once they both finish, collect the results without blocking by using .Result
I have this little console app test:
using System.Diagnostics;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
public static void Main(string[] args)
{
var run = TaskRunner();
Debug.WriteLine(run);
if (run.IsCompleted)
{
Debug.WriteLine("this worked!");
} else
{
Debug.WriteLine("this failed!");
}
}
public static async Task<string> TaskRunner()
{
var taskOne = OneAsync();
var taskTwo = TwoAsync();
var tasks = await Task.WhenAll(taskOne, taskTwo);
var retval = tasks[0] + tasks[1];
return retval;
}
public static Task<string> OneAsync()
{
return Task.Run(() =>
{
return "test1";
});
}
public static Task<string> TwoAsync()
{
return Task.Run(() =>
{
return "test2";
});
}
}
}
This currently prints this worked! to my Output window... However, if I comment out Debug.WriteLine(run); it prints this failed!... Why does the Task complete simply by being logged to the output window?
I'm trying to understand a huge problem in a complex piece of code and this little test is my MCVE to hopefully shed some light on what is happening behind the scenes.
This happens just by pure chance. The way you are starting your task is with Task.Run. This essentially creates a new thread on which the (synchronous) action is executed. It returns a task for the completion of that thread.
So OneAsync and TwoAsync will each spawn a new thread that then immediately returns a string. This will happen very quickly but there’s still some overhead for creating those threads which means that it won’t be instantaneous.
TaskRunner then calls both those methods (spawning the threads), and then asynchronously waits for both threads to finish. Since the threads are not completely instantly, this TaskRunner method also won’t complete instantly.
Now, in your main, you are starting the asynchronous TaskRunner, which we figured will take “a very short moment”. You do not await the task, so the execution continues immediately. Debug.WriteLine is executed to print something (it probably doesn’t really matter that it’s the task in question that is being printed), and then you are checking the state of the task.
Since printing stuff is relatively slow (compared to other operations), this is probably the reason why the tasks ends up being completed. And when you remove the printing, the if is just reached too quickly for the task to finish.
As you likely noticed, working like that with asynchronous tasks does not appear to be a good idea. That’s why you should always await the task when you depend on its result.
// note the *async* here; async main methods are supported with C# 7.1
public static async void Main(string[] args)
{
var run = TaskRunner();
// await the task
await run;
if (run.IsCompleted)
{
Debug.WriteLine("this worked!");
}
else
{
Debug.WriteLine("this failed!");
}
}

Await stops execution of thread and never continues

I have the following:
public async Task<bool> SearchForUpdatesAsync()
{
return await TaskEx.Run(() =>
{
if (!ConnectionChecker.IsConnectionAvailable())
return false;
// Check for SSL and ignore it
ServicePointManager.ServerCertificateValidationCallback += delegate { return (true); };
var configurations = UpdateConfiguration.Download(UpdateConfigurationFileUri, Proxy);
var result = new UpdateResult(configurations, CurrentVersion,
IncludeAlpha, IncludeBeta);
if (!result.UpdatesFound)
return false;
_updateConfigurations = result.NewestConfigurations;
double updatePackageSize = 0;
foreach (var updateConfiguration in _updateConfigurations)
{
var newPackageSize = GetUpdatePackageSize(updateConfiguration.UpdatePackageUri);
if (newPackageSize == null)
throw new SizeCalculationException(_lp.PackageSizeCalculationExceptionText);
updatePackageSize += newPackageSize.Value;
_packageOperations.Add(new UpdateVersion(updateConfiguration.LiteralVersion),
updateConfiguration.Operations);
}
TotalSize = updatePackageSize;
return true;
});
}
As you can see I'm using Microsoft.Bcl.
Now in my other class I wrote this code in a normal void:
TaskEx.Run(async delegate
{
// ...
_updateAvailable = await _updateManager.SearchForUpdatesAsync();
MessageBox.Show("Test");
});
The problem I have is that it executes _updateAvailable = await _updateManager.SearchForUpdatesAsync(); and then it doesn't continue the thread, it just stops as if there is nothing after that call. Visual Studio also tells me this after a while: Thread ... exited with code 259, so something seems to be still alive.
I debugged through it to search for any exceptions that could maybe be swallowed, but nothing, everything works fine and it executes the return-statement.
And that is what I don't understand, I never see the MessageBox and/or no code beyond this line's being executed.
After I talked to some friends, they confirmed that this shouldn't be. Did I make a horrible mistake when implementing async-await?
Thanks in advance, that's actually all I can say about that, I got no more information, I appreciate any tips and help as far as it's possible.
The main issue that you're having is that you're unnecessarily wrapping your method in TaskEx.Run() and you are probably experiencing deadlock somewhere.
Your method signature is currently:
public async Task<bool> SearchForUpdatesAsync()
This means the following:
async --> Doesn't actually do anything, but provides a "heads up" that await might be called within this method and that this method can be used as a runnable Task.
Task --> This method returns a runnable task that can be run asynchronously on the threadpool
<bool> --> This method actually returns bool when awaited.
The await TaskEx.Run() is unnecessarily since this says run this method and then don't return until after a value is available. This is most likely causing a synchronization problem. Removing this construct will make your method work properly, however you'll notice that now you have no reason to even include the async operator or the Task<T> portion since the method is actually synchronous anyway. Usually you're only going to use async identifier on the method signature if you have methods that you are going to call await on them.
Instead you have two options.
Whenever you want to call SearchForUpdates() you can wrap this in a Task<bool>.Run() to run it asynchronously (or the Bcl equivalent)
Since you are using WinForms you might be better off using a BackgroundWorker and just calling this method within it.
Regarding using the async-await pattern I think that this is a great article to use to make sure you're following best practices: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
The best practice is to have async all the way through your layers, and then call await or less desirably .Wait() / .Result at the final use site.
Also, try to keep your UI calls separate from the backend work, since you can run into synchronicity/thread-context issue.
public class WinFormsCode
{
private async Task WinsFormCodeBehindMethodAsync()
{
var updatesAvailable = await _updateManager.SearchForUpdatesAsync();
MessageBox.Show("Updates Available: " + updatesAvailable.ToString());
}
private void WinsFormCodeBehindMethodSync()
{
var updatesAvailable = _updateManager.SearchForUpdatesAsync().Result;
MessageBox.Show("Updates Available: " + updatesAvailable.ToString());
}
}
public class UpdateManager
{
public async Task<bool> SearchForUpdatesAsync()
{
return true;
}
}

How to track if an async/awaitable task is running

I'm trying to transition from the Event-based Asynchronous Pattern where I tracked running methods using unique id's and the asynoperationmanager. As this has now been dropped from Windows 8 Apps I'm trying to get a similar effect with Async/Await but can't quite figure out how.
What I'm trying to achieve is something like
private async Task updateSomething()
{
if(***the method is already running***)
{
runagain = true;
}
else
{
await someMethod();
if (runagain)
{
run the method again
}
}
}
The part I'm struggling with is finding out if the method is running. I've tried creating a Task and looking at the status of both that and the .status of the async method but they don't appear to be the correct place to look.
Thanks
UPDATE: This is the current code I use in .net 4 to achieve the same result. _updateMetaDataAsync is a class based on the Event-Based Asynchronous Pattern.
private void updateMetaData()
{
if (_updateMetaDataAsync.IsTaskRunning(_updateMetaDataGuid_CheckAllFiles))
{
_updateMetaDataGuid_CheckAllFiles_Again = true;
}
else
{
_updateMetaDataGuid_CheckAllFiles_Again = false;
_updateMetaDataAsync.UpdateMetaDataAsync(_updateMetaDataGuid_CheckAllFiles);
}
}
private void updateMetaDataCompleted(object sender, UpdateMetaDataCompletedEventArgs e)
{
if (_updateMetaDataGuid_CheckAllFiles_Again)
{
updateMetaData();
}
}
async/await itself is intended to be used to create sequential operations executed asynchronously from the UI thread. You can get it to do parallel operations, but generally the operations "join" back to the UI thread with some sort of result. (there's also the possibility of doing "fire-and-forget" types of asynchronous operations with await but it's not recommended). i.e. there's nothing inherent to async/await to support progress reporting.
You can get progress out of code using async/await; but you need to use new progress interfaces like IProgress<T>. For more info on progress reporting with async/await, see http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis.aspx. Migrating to this should just be a matter of calling an IProgress delegate instead of a Progress event.
If you're using a Task you've created, you can check the Task's Status property (or just see Task.IsCompleted if completion is the only state you are interested in).
That being said, await will not "return" until the operation either completes, raises an exception, or cancels. You can basically safely assume that, if you're still waiting on the "await", your task hasn't completed.
SemaphoreSlim queueToAccessQueue = new SemaphoreSlim(1);
object queueLock = new object();
long queuedRequests = 0;
Task _loadingTask;
public void RetrieveItems() {
lock (queueLock) {
queuedRequests++;
if (queuedRequests == 1) { // 1 is the minimum size of the queue before another instance is queued
_loadingTask = _loadingTask?.ContinueWith(async () => {
RunTheMethodAgain();
await queueToAccessQueue.WaitAsync();
queuedRequests = 0; // indicates that the queue has been cleared;
queueToAccessQueue.Release()
}) ?? Task.Run(async () => {
RunTheMethodAgain();
await queueToAccessQueue.WaitAsync();
queuedRequests = 0; // indicates that the queue has been cleared;
queueToAccessQueue.Release();
});
}
}
}
public void RunTheMethodAgain() {
** run the method again **
}
The added bonus is that you can see how many items are sitting in the queue!

Categories