Execute Bundles of Parallel Tasks in Series - c#

I have a GUI that allows users to make changes to various objects (which embody some internal rules), then click Save to write the changes to a database using EF6. When they make a change to some objects, I want to first deactivate all the currently active objects in the database (the order is not important), and then when that is completed, I would like to insert new, active objects (again, in any order).
I thought I would be able to achieve this by making two lists of tasks - one for deactivating objects (deactivate_Tasks) and the other for adding new objects (add_Tasks). I thought that I would then be able to await Task.WhenAll(deactivate_Tasks) to make sure that the first set of tasks completed in parallel, but in series with the second set, executed on the next line (await Task.WhenAll(add_Tasks)). Thus the additions would only occur once the deactivations have completed.
However, when I run the code, I get seemingly erratic results, with all the adding and deactivating tasks occurring in an unpredictable order. I don't know why this is and I would like to avoid it - any suggestions would be really welcome.
I have mocked up a sample of my code below to help - hopefully the method names are self-explanatory enough, but please ask if not. In the real case, there are more types of rule to be added and deactivated. I am using C# 4.8 and writing a windows WPF application using the MVVM framework as much as I can.
public class MyViewModel
{
private ICommand _saveCommand;
public ICommand SaveCommand
{
get
{
return _saveCommand ?? (_saveCommand = new RelayCommand(execute => Save(), canExecute => IsDirty));
}
set
{ _saveCommand = value; }
}
private RuleDataService _ruleDataService { get; set; }
public async void Save()
{
var add_Tasks = new List<Task<StatusCode>>();
var deactivate_Tasks = new List<Task<StatusCode>>();
if (CustomerRule_IsDirty)
{
add_Tasks.Add(_rulesDataService.CREATE_Rule(newCustomerRule));
if (existingCustomerRule != null)
{
deactivate_Tasks.Add(_rulesDataService.DEACTIVATE_Rule(existingCustomerRule));
}
}
if (WarehouseRule_IsDirty)
{
add_Tasks.Add(_rulesDataService.CREATE_Rule(newWarehouseRule));
if (existingWarehouseRule != null)
{
deactivate_Tasks.Add(_rulesDataService.DEACTIVATE_Rule(existingWarehouseRule))
}
}
//MY COMMENTS REFLECT WHAT I HOPED TO ACHIEVE, NOT WHAT ACTUALLY HAPPENS
//wait for all the deactivations to be done
await Task.WhenAll(deactivate_Tasks).ConfigureAwait(false);
//once everything is deactivated, add the replacements
await Task.WhenAll(add_Tasks).ConfigureAwait(false);
}
}
/// <summary>
/// Sample only - hopefully the methods names used above are self explanatory, but they all return a Task<StatusCode>
/// </summary>
public class RuleDataService
{
public async Task<StatusCode> DEACTIVATE_Rule(Customer_Rule customer_Rule)
{
using(var context = new DBContext())
{
context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
return await Task.Run(() =>
{
foreach (var existingRule in context.Customer_Rules.Where(r => r.CustomerName == customer_Rule.CustomerName && r.IsActive && r.RuleSetId != customer_Rule.RuleSetId))
{
existingRule.IsActive = false;
}
context.SaveChanges();
return StatusCode.TaskComplete;
}).ConfigureAwait(false);
}
}
public async Task<StatusCode> DEACTIVATE_Rule(Warehouse_Rule warehouse_Rule)
{
//basically the same as the other DEACTIVATE methods, just a different table
}
public async Task<StatusCode> CREATE_Rule(Customer_Rule customer_Rule)
{
//basically the same as the other DB methods, but performs an Add instead of an UPDATE
}
public async Task<StatusCode> CREATE_Rule(Warehouse_Rule warehouse_Rule)
{
//basically the same as the other DB methods, but performs an Add instead of an UPDATE
}
}
I have done a fair amount of googling for answers, but the answers only seem to give advice on how to run a series of tasks in parallel, which I have achieved, not how to bundle up in-series sets of parallel actions.

All async tasks are created "hot". In other words, when your code calls the method that returns a task, that method invocation is what starts the task. The task is in progress by the time it is returned. It's still in progress when it's added to the list.
So, if you want to delay the creation of the second batch, don't call those methods yet:
public async Task Save()
{
var deactivate_Tasks = new List<Task<StatusCode>>();
if (CustomerRule_IsDirty)
{
if (existingCustomerRule != null)
{
deactivate_Tasks.Add(_rulesDataService.DEACTIVATE_Rule(existingCustomerRule));
}
}
if (WarehouseRule_IsDirty)
{
if (existingWarehouseRule != null)
{
deactivate_Tasks.Add(_rulesDataService.DEACTIVATE_Rule(existingWarehouseRule))
}
}
await Task.WhenAll(deactivate_Tasks).ConfigureAwait(false);
var add_Tasks = new List<Task<StatusCode>>();
if (CustomerRule_IsDirty)
{
add_Tasks.Add(_rulesDataService.CREATE_Rule(newCustomerRule));
}
if (WarehouseRule_IsDirty)
{
add_Tasks.Add(_rulesDataService.CREATE_Rule(newWarehouseRule));
}
await Task.WhenAll(add_Tasks).ConfigureAwait(false);
}

await is akin to "continue execution when this task is done". Notably, it does not say anything at all about when the task is started. So your example code both add and deactivate tasks will run in parallel, resulting in the behavior you describe. The solution is to start the add tasks after the deactivate tasks. I.e.
// Create all deactivate tasks
if (CustomerRule_IsDirty && existingCustomerRule != null)
{
deactivate_Tasks.Add(_rulesDataService.DEACTIVATE_Rule(existingCustomerRule));
}
if (WarehouseRule_IsDirty && existingWarehouseRule != null)
{
deactivate_Tasks.Add(_rulesDataService.DEACTIVATE_Rule(existingWarehouseRule))
}
await Task.WhenAll(deactivate_Tasks).ConfigureAwait(false);
// Create all add tasks
if (CustomerRule_IsDirty)
{
add_Tasks.Add(_rulesDataService.CREATE_Rule(newCustomerRule));
}
if (WarehouseRule_IsDirty)
{
add_Tasks.Add(_rulesDataService.CREATE_Rule(newWarehouseRule));
}
await Task.WhenAll(add_Tasks).ConfigureAwait(false);
also, you are creating the DbContext object in another thread-context than where it is used. I would suggest moving the creation and disposal into the Task.Run(...) just to avoid any potential issues.

Related

Ensure blocking of database rows during the Entity Framework request

I have created service which communicates with my database. GetAvailableUserId service's method cannot be run simultaneously, because I don't want to return same user's id for two different calls. So far I have managed this:
public class UserService : IUserService
{
public int GetAvailableUserId()
{
using (var context = new UsersEntities())
{
using (var transaction = context.Database.BeginTransaction())
{
var availableUser = context.User
.Where(x => x.Available)
.FirstOrDefault();
if (availableUser == null)
{
throw new Exception("No available users.");
}
availableUser.Available = false;
context.SaveChanges();
transaction.Commit();
return availableUser.Id;
}
}
}
}
I wanted to test if service will work as intended, so I created simple console application to simulate synchronous requests:
Parallel.For(1, 100, (i, state) => {
var service = new UserServiceReference.UserServiceClient();
var id = service.GetAvailableUserId();
});
Unfortunately, It failed that simple test. I can see, that it returned same id for different for iterations.
Whats wrong there?
If I understood you correctly, you wan to lock method from other threads. If yesm then use lock:
static object lockObject = new object();
public class UserService : IUserService
{
public int GetAvailableUserId()
{
lock(lockObject )
{
// your code is omitted for the brevity
}
}
}
You need to spend some time and delve into the intricadies of SQL Server and EntityFramework.
Basically:
You need a database connection that handles repeatable results (which is a database connection string setting).
You need to wrap the interactions in EntityFramework within one transaction so that multiple instances do not possibly return the same result in the query and then make problems in the save.
Alternative method to achieve this is to catch DbUpdateConcurrencyException to check whether values in the row have changed since retrieving when you try to save.
So if e.g. the same record is retrieved twice. The first one to have the Available value updated in the database will cause the other one to thow concurrency exception when it tries to save because the value has changed since it was retrieved.
Microsoft - handling Concurrency Conflicts.
Add ConcurrencyCheck attribute above the Available property in your entity.
[ConcurrencyCheck]
public bool Available{ get; set; }
Then:
public int GetAvailableUserId()
{
using (var context = new UsersEntities())
{
try
{
var availableUser = context.User
.Where(x => x.Available)
.FirstOrDefault();
if (availableUser == null)
{
throw new Exception("No available users.");
}
availableUser.Available = false;
context.SaveChanges();
return availableUser.Id;
}
catch (DbUpdateConcurrencyException)
{
//If same row was already retrieved and updated to false, do not save, instead call the method again to get the next true row.
return GetAvailableUserId();
}
}
}

Execute Two Database Calls (with Two DbContexts) Simultaneously

I need to get results from two different DbContext (which target two different schemas of an Oracle database) to populate a page. I to want to execute both database queries (read only, no write operations) simultaneously and return the results when they're both done. Trouble is, I'm a serial dude in a parallel world, and I don't know jack about Async/Await/TPL etc…
I have a controller Action that looks basically like this:
public Task<IActionResult> Foo(MyViewModel vm)
{
if (!ModelState.IsValid) return Task.Run(()=> (IActionResult)View(vm));
var filter = new FilterObject(vm);
var firstTask = _firstContext.FilterItems(filter); // returns Task<IQueryable<Items>>
var secondTask = _secondContext.FilterItems(filter); // returns Task<IQueryable<Items>>
vm.Result.Clear();
vm.Results.AddRange(firstTask.Result);
vm.Results.AddRange(secondTask.Result);
return Task.Run(()=> (IActionResult)View("Index", vm));
}
My DbContext calls the filter to do its job:
public class FirstContext : DbContext
{
public DbQuery<Items> Items{get;set;}
public Task<IQueryable<Items>> FilterItems(FilterObject filter)
{
filter.ApplyTo(Items.AsQueryable());
}
}
... and my FilterObject modifies the IQueryable:
public class FilterObject
{
public Task<IQueryable<Items>> ApplyTo(IQueryable<Items> items)
{
return Task.Run(()=> items
.Where(item => item.Property1.Contains(this.Property1))
.Where(item => item.Other == this.OtherString)
// more Where clauses ad nauseum; you get the idea
}
}
Am I doing this anywhere close to right? As I understand it, the call to the database won't actually execute until the AddRange method, because the Task.Result is an IQueryable - so that seems wrong to me: the AddRange() methods will execute synchronously, not asynchronously, right? All I've done is build two queries, not execute them. I'm guessing that I need to return a List<Item> from the DbContext, which will cause each query to actually execute... but is that the only change I need to make so that these calls happen at the same time, without blocking each other?
As always, any guidance is immensely appreciated.
Drop all your Task work from the IQueryables you have. That's one layer too much. Keep it simple. You have a query. That will return an IQueryable<>. Then you use ToListAsync to get the results asynchronously:
public async Task<IActionResult> Foo(MyViewModel vm)
{
if (!ModelState.IsValid) return View(vm);
var filter = new FilterObject(vm);
var firstTask = _firstContext.YourQueryable.ToListAsync();
var secondTask = _secondContext.YourQueryable.ToListAsync();
var firstResult = await firstTask;
var secondResult = await secondTask;
vm.Result.Clear();
vm.Results.AddRange(firstResult);
vm.Results.AddRange(secondResult);
return View("Index", vm);
}
Task.Run will move the task into another thread, which isn't really necessary. Use async and await, which will run everything on the same thread, but will allow other work to be done on the same thread while waiting for the results. For example, after firing the first query, it can start the second query while waiting for the first to finish.
It seems like FilterItems and ApplyTo are just modifying the query, and not actually executing the result, so I don't see why they need to return a Task at all. You can use ToListAsync() to actually execute the query, after the query has been built.
For example:
public async Task<IActionResult> Foo(MyViewModel vm)
{
if (!ModelState.IsValid) return Task.Run(()=> (IActionResult)View(vm));
var filter = new FilterObject(vm);
//This will execute the queries
var firstTask = _firstContext.FilterItems(filter).ToListAsync();
var secondTask = _secondContext.FilterItems(filter).ToListAsync();
vm.Result.Clear();
vm.Results.AddRange(await firstTask); //add the first set when they're available
vm.Results.AddRange(await secondTask); //add the second set when they're available
return View("Index", vm);
}
You didn't have a return in FilterItems, but I assumed it should be there:
public class FirstContext : DbContext
{
public DbQuery<Items> Items{get;set;}
public IQueryable<Items> FilterItems(FilterObject filter)
{
return filter.ApplyTo(Items.AsQueryable());
}
}
public class FilterObject
{
public IQueryable<Items> ApplyTo(IQueryable<Items> items)
{
return items
.Where(item => item.Property1.Contains(this.Property1))
.Where(item => item.Other == this.OtherString)
// more Where clauses ad nauseum; you get the idea
}
}

ReactiveUI 6 instant search (MVVM)

I would like to react to user's typing within a text box.
Actually my question is similar to what has already been posted at Reactive Extensions Instant Search for WPF/MVVM.
Now that we're at the release 6 of ReactiveUI, the previous code is out of date. How can I implement it (with MVVM, i.e. not using events)?
The compelling example # http://reactiveui.net/ should help alot. You also want to make sure your xaml TextBox uses the UpdateSourceTrigger
<TextBox Text="{Binding SearchQuery, UpdateSourceTrigger=PropertyChanged}" Width="50" />
Code from RXUI copied here:
public class SearchViewModel : ReactiveObject, IRoutableViewHost
{
public ReactiveList<SearchResults> SearchResults { get; set; }
private string searchQuery;
public string SearchQuery {
get { return searchQuery; }
set { this.RaiseAndSetIfChanged(ref searchQuery, value); }
}
public ReactiveCommand<List<SearchResults>> Search { get; set; }
public ISearchService SearchService { get; set; }
}
and the constructor code
// Constructor
public SearchViewModel(ISearchService searchService = null)
{
SearchService = searchService ?? Locator.Current.GetService<ISearchService>();
// Here we're describing here, in a *declarative way*, the conditions in
// which the Search command is enabled. Now our Command IsEnabled is
// perfectly efficient, because we're only updating the UI in the scenario
// when it should change.
var canSearch = this.WhenAny(x => x.SearchQuery, x => !String.IsNullOrWhiteSpace(x.Value));
// ReactiveCommand has built-in support for background operations and
// guarantees that this block will only run exactly once at a time, and
// that the CanExecute will auto-disable and that property IsExecuting will
// be set according whilst it is running.
Search = ReactiveCommand.CreateAsyncTask(canSearch, async _ => {
return await searchService.Search(this.SearchQuery);
});
// ReactiveCommands are themselves IObservables, whose value are the results
// from the async method, guaranteed to arrive on the UI thread. We're going
// to take the list of search results that the background operation loaded,
// and them into our SearchResults.
Search.Subscribe(results => {
SearchResults.Clear();
SearchResults.AddRange(results);
});
// ThrownExceptions is any exception thrown from the CreateAsyncTask piped
// to this Observable. Subscribing to this allows you to handle errors on
// the UI thread.
Search.ThrownExceptions
.Subscribe(ex => {
UserError.Throw("Potential Network Connectivity Error", ex);
});
// Whenever the Search query changes, we're going to wait for one second
// of "dead airtime", then automatically invoke the subscribe command.
this.WhenAnyValue(x => x.SearchQuery)
.Throttle(TimeSpan.FromSeconds(1), RxApp.MainThreadScheduler)
.InvokeCommand(this, x => x.Search);
}

What is the best way to use an asynchronous API with ReactiveUI to populate a collection?

Let us say I have this ReactiveUI view model structure, with Model being some arbitrary model type.
class ViewModel : ReactiveObject
{
private readonly ReactiveList<Model> _models;
public IReactiveList<Model> Models { get { return _models; } }
public IReactiveCommand LoadModels { get; private set; }
public bool LoadingModels { get; private set; } // Notifies;
}
And these models come from a task-based asynchronous API modeled by this interface:
interface ITaskApi
{
Task<IEnumerable<Model>> GetModelsAsync();
}
After taking a look at how Octokit.net's reactive library was written, I wrote the following class to adapt the API to a reactive world:
class ObservableApi
{
private readonly ITaskApi _taskApi;
public IObservable<Model> GetModels() {
return _taskApi.GetModelsAsync().ToObservable().SelectMany(c => c);
}
}
And now, I have written the following ways to implement loading of models inside of the the LoadModels command, in the ViewModel() constructor:
// In both cases, we want the command to be disabled when loading:
LoadModels = new ReactiveCommand(this.WhenAny(x => x.LoadingModels, x => !x.Value));
// First method, with the Observable API;
LoadModels.Subscribe(_ =>
{
LoadingModels = true;
_models.Clear();
observableClient.GetModels().ObserveOnDispatcher()
.Subscribe(
m => _models.Add(m),
onCompleted: () => { LoadingModels = false; });
});
// Second method, with the task API;
LoadModels.Subscribe(async _ =>
{
LoadingModels = true;
try {
var loadedModels = await taskClient.GetModelsAsync();
_models.Clear();
_models.AddRange(loadedModels);
} catch (Exception ex) {
RxApp.DefaultExceptionHandler.OnNext(ex);
} finally {
LoadingModels = false;
}
});
While I think that both ways will do the job, I have the following misgivings:
In the first sample, should I dispose the inner subscription or will that be done when the inner observable completes or errors?
In the second sample, I know that exceptions raised in the GetModelsAsync method will be swallowed.
What is the "best", most idiomatic way to populate a ReactiveList<T> from an asynchronous enumeration (either IObservable<T> or Task<IEnumerable<T>> (or would IObservable<IEnumerable<T>> be better?))?
After taking a look at how Octokit.net's reactive library was written, I wrote the following class to adapt the API to a reactive world:
While you sometimes want to do this (i.e. flatten the collection), it's usually more convenient to just leave it as IEnumerable<T> unless you then plan to invoke an async method on each item in the list. Since we just want to stuff everything in a List, we don't want to do this. Just leave it as Task<T>
In the first sample, should I dispose the inner subscription or will that be done when the inner observable completes or errors?
Any time you have a Subscribe inside another Subscribe, you probably instead want the SelectMany operator. However, there is a better way to do what you're trying to do, you should check out this docs article for more info.
So, here's how I would write your code:
// In both cases, we want the command to be disabled when loading:
LoadModels = new ReactiveCommand();
LoadModels.RegisterAsyncTask(_ => taskClient.GetModelsAsync())
.Subscribe(items =>
{
// This Using makes it so the UI only looks at the collection
// once we're totally done updating it, since we're basically
// changing it completely.
using (_models.SuppressChangeNotifications())
{
_models.Clear();
_models.AddRange(items);
}
});
LoadModels.ThrownExceptions
.Subscribe(ex => Console.WriteLine("GetModelsAsync blew up: " + ex.ToString());
// NB: _loadingModels is an ObservableAsPropertyHelper<bool>
LoadModels.IsExecuting
.ToProperty(this, x => x.LoadingModels, out _loadingModels);

Is there a well-defined pattern for binding controls to asynchronous data?

Can you tell whether the following snippets are correctly binding to an asynchronous data source ?
While it seems to be working, i.e : UI does not freeze, I'm not entirely sure about the correctness as the MSDN documentation does not really talk about binding to 'async' methods in these docs :
Binding.IsAsync
ObjectDataProvider.IsAsynchronous
<pages:HottestPageProxy x:Key="PageProxy" ></pages:HottestPageProxy>
<ObjectDataProvider x:Key="DataProviderArtists" IsAsynchronous="True" ObjectInstance="{StaticResource PageProxy}" MethodName="GetArtists">
<ObjectDataProvider.MethodParameters>
<system:String>Grabbing artists !</system:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
(HottestPageProxy object is a small helper that provides data for the controls)
public class HottestPageProxy
{
[UsedImplicitly]
public async Task<ArtistsQuery> GetArtists([CallerMemberName] string memberName = "")
{
Console.WriteLine(memberName);
string apiKey = App.GetApiKey();
Task<ArtistsQuery> topHottt = Queries.ArtistTopHottt(new ArtistTopHotttParameters
{
ApiKey = apiKey,
Results = 100,
Buckets = new[] {ArtistTopHotttBuckets.Hotttnesss}
});
return (await topHottt);
}
}
EDIT : method that 'await topHottt' calls
public static async Task<ArtistsQuery> ArtistTopHottt(ArtistTopHotttParameters parameters)
{
if (parameters == null) throw new ArgumentNullException("parameters");
return await Get<ArtistsQuery>(parameters);
}
private static async Task<T> Get<T>(Parameters parameters) where T : Query
{
if (parameters == null) throw new ArgumentNullException("parameters");
ValidateParameters(parameters);
string url = parameters.GetQueryUrl();
var value = new Uri(url);
using (var client = GetHttpClient())
using (var message = await client.GetAsync(url))
{
// fetch message content (removed)
return GetQueryResultObject<T>(s);
}
}
private static T GetQueryResultObject<T>(string json) where T : class
{
// create T from Json string (removed)
return t;
}
EDIT using AsyncEx
Using your library works though the syntax now is :
<ItemsControl x:Name="ItemsControlTopHott"
ItemsSource="{Binding ... Path=Artists.Result.Artists ...}">
</ItemsControl>
Is 'Artists.Result.Artists' really what you expect me to use ? :)
The new syntax makes it more confusing as the source is :
public sealed class ArtistsQuery : Query
{
public List<Artist> Artists { get; set; }
}
Not a big deal but if I could avoid such syntax that'd be great.
You said that .Result might bring a deadlock, did I miss something in implementing your solution then ?
Artists.PropertyChanged event raised the following messages :
Status: RanToCompletion
IsCompleted: True
IsSuccessfullyCompleted: True
Result: Success
I'll give a try to .ConfigureAwait(false) as you've mentioned in your post to see how it goes with it.
Forgot to mention, actually my implementation using .Result indeed does not block the UI as the typical time to get the result is a few seconds; I'd have seen the UI freeze. It seems right ... but I'm not certain whether it's correct, hence my question.
As others have noted, the "asynchronous" members in WPF types have nothing to do with async and await.
You do have a problem in your binding; your path is using Task.Result, which will block the UI thread until the query is complete. Also, using Result brings up the possibility of a deadlock that I describe on my blog.
I have another blog entry that deals with async properties, in particular how to data-bind to properties that are (logically) asynchronous. My AsyncEx library has a type called NotifyTaskCompletion that allows you to data-bind more naturally to an asynchronous Task.
So, e.g., you could do something like this:
public class HottestPageProxy
{
public HottestPageProxy()
{
Artists = NotifyTaskCompletion.Create(GetArtists());
}
public INotifyTaskCompletion<ArtistsQuery> Artists { get; private set; }
private Task<ArtistsQuery> GetArtists()
{
string apiKey = App.GetApiKey();
return Queries.ArtistTopHottt(new ArtistTopHotttParameters
{
ApiKey = apiKey,
Results = 100,
Buckets = new[] {ArtistTopHotttBuckets.Hotttnesss}
});
}
}
Then you can data-bind to several different properties on INotifyTaskCompletion<T>, including IsCompleted, ErrorMessage, and Result (which does not block; it will return default(T) if the task is not completed).

Categories