A MessageReceived handler is blocking the gateway task - c#

I want to send a message to everyone but I always get "A MessageReceived handler is blocking the gateway task." when downloading Users.
[Command("testrole")]
public async Task dmeveryone()
{
var guild = Program._client.GetGuild(Context.Guild.Id) as IGuild;
await Context.Guild.DownloadUsersAsync();
await Task.Delay(500);
var users = await guild.GetUsersAsync();
var recipients = users
.OfType<IGuildUser>()
.Where
(
u => !u.IsBot && !u.IsWebhook
);
var tasks = recipients
.Select
(
r => r.SendMessageAsync("Hi")
);
try
{
await Task.WhenAll(tasks);
}
catch
{
var exceptions = tasks.Where(t => t.Exception != null)
.Select(t => t.Exception);
}
}
this is how I use it, I tried using:
[Command("testrole", RunMode.Async)]
but that won't work aswell..

Related

run multiple task and await for all tasks completes

I need to run multiple task to access to database and to wait to all task finished to obtain the result and assign it to my viewmodel, i try many sample but i have never have the result, any help please, this my code
var model = new AggregationViewModel();
var loadDataTasks = new Task[]
{
Task.Run(async () =>model.Alive = await _repository.GetCountAsync<filter>(Predicate)),
Task.Run(async () => model.Delay = await _repository.GetCountAsync<Flight>(predicate.And(x => x.Status == "refused")))
};
try
{
await Task.WhenAll(loadDataTasks);
foreach (var item in loadDataTasks)
{
}
}
catch (Exception ex)
{
}
Check this out:
var task1 = _repository.GetCountAsync<filter>(Predicate);
var task2 = _repository.GetCountAsync<Flight>(predicate.And(x => x.Status == "refused"));
await Task.WhenAll(task1, task2); //wait both tasks to finish
model.Alive = await task1;
model.Delay = await task2;
PS: the function, which the above code is placed, is needed to be async for the above scenario.
Try this code:
var model = new AggregationViewModel();
//----------------------------------------
var tasks = new List<Task<int>>();
//Add CountA
tasks.Add(_repository.GetCountAsync<filter>(Predicate));
//Add CountB
tasks.Add(_repository.GetCountAsync<Flight>(predicate.And(x => x.Status == "refused")));
//----------------------------------------
// Create a task with "allTasks" name to wait to complete all tasks
Task allTasks = Task.WhenAll(tasks);
try {
// Wait to compelete "allTask"
allTasks.Wait();
}
catch(AggregateException)
{}
//----------------------------------------
//Working on the results
if (allTasks.Status == TaskStatus.RanToCompletion) {
model.CountA=allTasks.Result[0]
model.CountB=allTasks.Result[1]
}
// Display information on faulted tasks.
else {
foreach (var t in tasks) {
Console.WriteLine("Task {0}: {1}", t.Id, t.Status);
}
}

How to get the first value that specifies a condition out of multiple tasks [duplicate]

I want to execute several asynchronous tasks concurrently. Each task will run an HTTP request that can either complete successfully or throw an exception. I need to await until the first task completes successfully, or until all the tasks have failed.
How can I implement an overload of the Task.WhenAny method that accepts a predicate, so that I can exclude the non-successfully completed tasks?
Wait for any task and return the task if the condition is met. Otherwise wait again for the other tasks until there is no more task to wait for.
public static async Task<Task> WhenAny( IEnumerable<Task> tasks, Predicate<Task> condition )
{
var tasklist = tasks.ToList();
while ( tasklist.Count > 0 )
{
var task = await Task.WhenAny( tasklist );
if ( condition( task ) )
return task;
tasklist.Remove( task );
}
return null;
}
simple check for that
var tasks = new List<Task> {
Task.FromException( new Exception() ),
Task.FromException( new Exception() ),
Task.FromException( new Exception() ),
Task.CompletedTask, };
var completedTask = WhenAny( tasks, t => t.Status == TaskStatus.RanToCompletion ).Result;
if ( tasks.IndexOf( completedTask ) != 3 )
throw new Exception( "not expected" );
public static Task<T> GetFirstResult<T>(
ICollection<Func<CancellationToken, Task<T>>> taskFactories,
Predicate<T> predicate) where T : class
{
var tcs = new TaskCompletionSource<T>();
var cts = new CancellationTokenSource();
int completedCount = 0;
// in case you have a lot of tasks you might need to throttle them
//(e.g. so you don't try to send 99999999 requests at the same time)
// see: http://stackoverflow.com/a/25877042/67824
foreach (var taskFactory in taskFactories)
{
taskFactory(cts.Token).ContinueWith(t =>
{
if (t.Exception != null)
{
Console.WriteLine($"Task completed with exception: {t.Exception}");
}
else if (predicate(t.Result))
{
cts.Cancel();
tcs.TrySetResult(t.Result);
}
if (Interlocked.Increment(ref completedCount) == taskFactories.Count)
{
tcs.SetException(new InvalidOperationException("All tasks failed"));
}
}, cts.Token);
}
return tcs.Task;
}
Sample usage:
using System.Net.Http;
var client = new HttpClient();
var response = await GetFirstResult(
new Func<CancellationToken, Task<HttpResponseMessage>>[]
{
ct => client.GetAsync("http://microsoft123456.com", ct),
ct => client.GetAsync("http://microsoft123456.com", ct),
ct => client.GetAsync("http://microsoft123456.com", ct),
ct => client.GetAsync("http://microsoft123456.com", ct),
ct => client.GetAsync("http://microsoft123456.com", ct),
ct => client.GetAsync("http://microsoft123456.com", ct),
ct => client.GetAsync("http://microsoft123456.com", ct),
ct => client.GetAsync("http://microsoft.com", ct),
ct => client.GetAsync("http://microsoft123456.com", ct),
ct => client.GetAsync("http://microsoft123456.com", ct),
},
rm => rm.IsSuccessStatusCode);
Console.WriteLine($"Successful response: {response}");
public static Task<Task<T>> WhenFirst<T>(IEnumerable<Task<T>> tasks, Func<Task<T>, bool> predicate)
{
if (tasks == null) throw new ArgumentNullException(nameof(tasks));
if (predicate == null) throw new ArgumentNullException(nameof(predicate));
var tasksArray = (tasks as IReadOnlyList<Task<T>>) ?? tasks.ToArray();
if (tasksArray.Count == 0) throw new ArgumentException("Empty task list", nameof(tasks));
if (tasksArray.Any(t => t == null)) throw new ArgumentException("Tasks contains a null reference", nameof(tasks));
var tcs = new TaskCompletionSource<Task<T>>();
var count = tasksArray.Count;
Action<Task<T>> continuation = t =>
{
if (predicate(t))
{
tcs.TrySetResult(t);
}
if (Interlocked.Decrement(ref count) == 0)
{
tcs.TrySetResult(null);
}
};
foreach (var task in tasksArray)
{
task.ContinueWith(continuation);
}
return tcs.Task;
}
Sample usage:
var task = await WhenFirst(tasks, t => t.Status == TaskStatus.RanToCompletion);
if (task != null)
var value = await task;
Note that this doesn't propagate exceptions of failed tasks (just as WhenAny doesn't).
You can also create a version of this for the non-generic Task.
Here is an attempted improvement of the excellent Eli Arbel's answer. These are the improved points:
An exception in the predicate is propagated as a fault of the returned task.
The predicate is not called after a task has been accepted as the result.
The predicate is executed in the original SynchronizationContext. This makes it possible to access UI elements (if the WhenFirst method is called from a UI thread)
The source IEnumerable<Task<T>> is enumerated directly, without being converted to an array first.
public static Task<Task<T>> WhenFirst<T>(IEnumerable<Task<T>> tasks,
Func<Task<T>, bool> predicate)
{
if (tasks == null) throw new ArgumentNullException(nameof(tasks));
if (predicate == null) throw new ArgumentNullException(nameof(predicate));
var tcs = new TaskCompletionSource<Task<T>>(
TaskCreationOptions.RunContinuationsAsynchronously);
var pendingCount = 1; // The initial 1 represents the enumeration itself
foreach (var task in tasks)
{
if (task == null) throw new ArgumentException($"The {nameof(tasks)}" +
" argument included a null value.", nameof(tasks));
Interlocked.Increment(ref pendingCount);
HandleTaskCompletion(task);
}
if (Interlocked.Decrement(ref pendingCount) == 0) tcs.TrySetResult(null);
return tcs.Task;
async void HandleTaskCompletion(Task<T> task)
{
try
{
await task; // Continue on the captured context
}
catch { } // Ignore exception
if (tcs.Task.IsCompleted) return;
try
{
if (predicate(task))
tcs.TrySetResult(task);
else
if (Interlocked.Decrement(ref pendingCount) == 0)
tcs.TrySetResult(null);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
}
}
Another way of doing this, very similar to Sir Rufo's answer, but using AsyncEnumerable and Ix.NET
Implement a little helper method to stream any task as soon as it's completed:
static IAsyncEnumerable<Task<T>> WhenCompleted<T>(IEnumerable<Task<T>> source) =>
AsyncEnumerable.Create(_ =>
{
var tasks = source.ToList();
Task<T> current = null;
return AsyncEnumerator.Create(
async () => tasks.Any() && tasks.Remove(current = await Task.WhenAny(tasks)),
() => current,
async () => { });
});
}
One can then process the tasks in completion order, e.g. returning the first matching one as requested:
await WhenCompleted(tasks).FirstOrDefault(t => t.Status == TaskStatus.RanToCompletion)
Just wanted to add on some of the answers #Peebo and #SirRufo that are using List.Remove (because I can't comment yet)
I would consider using:
var tasks = source.ToHashSet();
instead of:
var tasks = source.ToList();
so removing would be more efficient

Making parallel api calls and handling each response asynchronously in c#

I have a scenario where I need to make multiple api calls (same api with different parameters) parallely in c# (Xamarin iOS and Xamarin Android). And I don't want to wait for all tasks to complete, instead whenever a response comes I should process it and update the UI accordingly.
Method that needs to be called multiple times
public async Task<Response> GetProductsAsync(int categoryId, int pageNo = -1, int pageSize = -1)
{
try
{
string url = "";
if (pageNo == -1 || pageSize == -1)
url = $"catalog/v1/categories/{categoryId}/products";
else
url = $"catalog/v1/categories/{categoryId}/products?page-number={pageNo}&page-size={pageSize}";
var response = await client.GetAsync(url);
string responseString = await response.Content.ReadAsStringAsync();
GetParsedData(response.IsSuccessStatusCode, responseString);
}
catch (Exception e)
{
apiResponse.status = "internalError";
apiResponse.data = e.Message;
}
return apiResponse;
}
From calling function you may write the code as below
public void CallingFunctionToGetProductsAsync() {
Task.Run(async () =>
{
var response = await GetProductsAsync(1);
ProcessResponse(response);
});
Task.Run(async () =>
{
var response = await GetProductsAsync(2);
ProcessResponse(response);
});
}
This is how you can wait for multiple tasks asynchron and update the UI whenever any of them completes.
async Task GetSomeProductsAsync( IEnumerable<int> categoryIds )
{
List<Task<Response>> tasks = categoryIds
.Select( catId => GetProductsAsync( catId ) )
.ToList();
while ( tasks.Any() )
{
var completed = await Task.WhenAny( tasks );
tasks.Remove( completed );
var response = completed.Result;
// update the ui from this response
}
}
As a side note:
You should add ConfigureAwait(false) to your awaiting code in GetProducsAsync to avoid uneccessary sync with the caller thread (wich would be the UI here)
public async Task<Response> GetProductsAsync(int categoryId, int pageNo = -1, int pageSize = -1)
{
try
{
string url = "";
if (pageNo == -1 || pageSize == -1)
url = $"catalog/v1/categories/{categoryId}/products";
else
url = $"catalog/v1/categories/{categoryId}/products?page-number={pageNo}&page-size={pageSize}";
var response = await client.GetAsync(url).ConfigureAwait(false);
string responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
GetParsedData(response.IsSuccessStatusCode, responseString);
}
catch (Exception e)
{
apiResponse.status = "internalError";
apiResponse.data = e.Message;
}
return apiResponse;
}
You can read more about it in Stephen Cleary's blog article: Don't block on Async Code

A second operation started on this context before a previous asynchronous operation completed

Message:
"System.NotSupportedException was unhandled
Message: An unhandled exception of type 'System.NotSupportedException' occurred in mscorlib.dll
Additional information: A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe."
Code:
public async Task<IEnumerable<UserLangDTO>> ImportLang(int userId)
{
var userLangs = new List<UserLangDTO>();
using (FirstContext ctx = new FirstContext())
{
if (await (ctx.UserLang.AnyAsync(u => u.UserId == userId)) == false)
//some exception here
userLangs = await ctx.UserLang.AsNoTracking()
.Where(ul => ul.UserId == userId)
.Join(ctx.Language,
u => u.LangID,
l => l.LangID,
(u, l) => new { u, l })
.Join(ctx.Level,
ul => ul.u.LevelID,
le => le.LevelID,
(ul, le) => new { ul, le })
.Select(r => new UserLangDTO
{
UserId = r.ul.u.UserId,
Language = r.ul.l.Language,
Level = r.le.Level,
}).ToListAsync().ConfigureAwait(false);
}
using (SecondContext ctx = new SecondContext())
{
if ( await (ctx.UserLangs.AnyAsync(u => u.UserId == userId)) == true && userLangs.Any())
ctx.UserLangs.RemoveRange(ctx.UserLangs.Where(u => u.UserId == userId));
if (await hasUserLangs && userLangs.Any())
{
userLangs.ForEach(async l =>
{
var userLanguage = new UserLang();
userLanguage.UserId = userId;
userLanguage.LanguageId = await ctx.Languages.AsNoTracking()
.Where(la => la.NameEn == l.Language)
.Select(la => la.Id).FirstOrDefaultAsync().ConfigureAwait(false);
userLanguage.LevelId = await ctx.Levels.AsNoTracking()
.Where(la => la.NameEn == l.Language)
.Select(la => la.Id).FirstOrDefaultAsync().ConfigureAwait(false);
ctx.UserLangs.Add(userLanguage);
});
}
await ctx.SaveChangesAsync().ConfigureAwait(false);
}
return userLangs;
}
What I Tried:
I'm not sure what I'm doing wrong, I tried different stuff like :
1.
await Task.Run(() => Parallel.ForEach(strings, s =>
{
    DoSomething(s);
}));
2.
var tasks = userLangs.Select(async l =>
{
//rest of the code here
}
await Task.WhenAll(tasks);
3.
var tasks = userLangs.Select(async l =>
{
//rest of the code here
}
await Task.WhenAll(tasks);
await ctx.SaveChangesAsync().ConfigureAwait(false);
Other trial and error attempts, that i do not rember now
What am I doing wrong?
Here's your problem:
userLangs.ForEach(async
This is creating an async void method, because ForEach does not understand asynchronous delegates. So the body of the ForEach will be run concurrently, and Entity Framework does not support concurrent asynchronous access.
Change the ForEach to a foreach, and you should be good:
foreach (var l in userLangs)
{
var userLanguage = new UserLang();
userLanguage.UserId = userId;
userLanguage.LanguageId = await ...
}
For more information, see the "avoid async void" guidance in my Async Best Practices article.
For those who have the ability to use .NET 6, there is now a Parallel.ForEachAsync()
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.parallel.foreachasync?view=net-6.0
https://www.hanselman.com/blog/parallelforeachasync-in-net-6

Pubnub perform sync request

I have this asynchronous request:
Pubnub pn = new Pubnub(publishKey, subscribeKey, secretKey, cipherKey, enableSSL);
pn.HereNow("testchannel", res => //doesn't return a Task
{ //response
}, err =>
{ //error response
});
The problem is that I don't know how to run it synchronously. Please help.
I'm not familiar with pubnub, but what you're trying to achieve should be as simple as this:
Pubnub pn = new Pubnub(publishKey, subscribeKey, secretKey, cipherKey, enableSSL);
var tcs = new TaskCompletionSource<PubnubResult>();
pn.HereNow("testchannel", res => //doesn't return a Task
{ //response
tcs.SetResult(res);
}, err =>
{ //error response
tcs.SetException(err);
});
// blocking wait here for the result or an error
var res = tcs.Task.Result;
// or: var res = tcs.Task.GetAwaiter().GetResult();
Note that doing asynchronous stuff synchronously is not recommend. You should look at using async/await, in which case you'd do:
var result = await tcs.Task;
I solved this issue using the #Noseratio ideia with a simple enhancement.
private Task<string> GetOnlineUsersAsync()
{
var tcs = new TaskCompletionSource<string>();
_pubnub.HereNow<string>(MainChannel,
res => tcs.SetResult(res),
err => tcs.SetException(new Exception(err.Message)));
return tcs.Task;
}
// using
var users = await GetOnlineUsersAsync();

Categories

Resources